Since based on your question tag you are using MOXy:
MOXy allows bidirectional mappings via the @XmlInverseReference
extension (you will need to use EclipseLink 2.5.0 or later to have the relationship writeable in both directions):
MOXy also allows you to marshal a subset of the data using the Object Graphs extension:
Note
Below is what the answer should be, but there appears to be a marshalling bug wrt @XmlElementWrapper
and @XmlInverseReference
.
Java Model
MovieImpl
import java.util.Collection;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
@XmlRootElement(name="movie")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlNamedObjectGraph(
name="partial",
attributeNodes={
@XmlNamedAttributeNode("_id"),
@XmlNamedAttributeNode(value="_director", subgraph="partial"),
@XmlNamedAttributeNode(value="_actors", subgraph="partial")
},
subgraphs={
@XmlNamedSubgraph(
name="location",
attributeNodes = {
@XmlNamedAttributeNode("_id"),
@XmlNamedAttributeNode("_name")
}
)
}
)
@Entity
public class MovieImpl implements Movie {
@XmlElement(name="id")
@Id
@Column(name = "movieId", unique = true)
@GeneratedValue(strategy = GenerationType.IDENTITY)
int _id;
@XmlElement(name="director", type=PersonImpl.class)
@ManyToOne(fetch = FetchType.LAZY, targetEntity = PersonImpl.class)
@JoinColumn(name = "directorId")
Person _director;
@XmlElementWrapper(name="actors")
@XmlElement(name="actor", type=PersonImpl.class)
@XmlInverseReference(mappedBy="_actors")
@ManyToMany(fetch = FetchType.LAZY, cascade = CascadeType.ALL, targetEntity = PersonImpl.class)
@JoinTable(name = "movie_has_actors", joinColumns = { @JoinColumn(name = "movieId", nullable = false) }, inverseJoinColumns = { @JoinColumn(name = "personId", nullable = false) })
Collection<Person> _actors;
public Collection<Person> getActors() {
return _actors;
}
}
PersonImpl
import java.util.Collection;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
@XmlRootElement(name="actor")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlNamedObjectGraph(
name="partial",
attributeNodes={
@XmlNamedAttributeNode("_id"),
@XmlNamedAttributeNode("_name"),
@XmlNamedAttributeNode(value="_movies", subgraph="partial")
},
subgraphs={
@XmlNamedSubgraph(
name="location",
attributeNodes = {
@XmlNamedAttributeNode("_id"),
@XmlNamedAttributeNode("_name")
}
)
}
)
@Entity
public class PersonImpl implements Person {
@XmlElement(name="id")
private int _id;
@XmlElement(name="name")
private String _name;
@XmlElementWrapper(name="movies")
@XmlElement(name="movie", type=MovieImpl.class)
@XmlInverseReference(mappedBy="_actors")
@ManyToMany(mappedBy = "_actors", targetEntity = MovieImpl.class)
private Collection<Movie> _movies;
}
Demo Code
Demo
import java.io.File;
import javax.xml.bind.*;
import org.eclipse.persistence.jaxb.MarshallerProperties;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(MovieImpl.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum21764131/input.xml");
Movie movie = (Movie) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(MarshallerProperties.OBJECT_GRAPH, "partial");
marshaller.marshal(movie.getActors().toArray()[0], System.out);
}
}