I am wondering if it is possible to have JAXB not to create Java object for XML elements that serve as wrappers. For example, for XML of the following structure
<root>
<wrapper>
<entity/>
</wrapper>
</root>
I do not want an object for <wrapper> to be created at all. So for a class like
class Root {
private Entity entity;
}
the <entity> element should be unmarshalled directly into the entity field.
Is it possible to achieve with JAXB?
Although it requires extra coding, the desired unmarshalling is accomplished in the following way using a transient wrapper object:
#XmlRootElement(name = "root")
public class Root {
private Entity entity;
static class Entity {
}
static class EntityWrapper {
#XmlElement(name = "entity")
private Entity entity;
public Entity getEntity() {
return entity;
}
}
#XmlElement(name = "wrapper")
private void setEntity(EntityWrapper entityWrapper) {
entity = entityWrapper.getEntity();
}
}
EclipseLink MOXy offers a JAXB 2.2 implementation with extensions. One of the extended capabilities is to use XPath to navigate through layers of the XML you don't want in you domain model.
If you look at:
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted/MOXyExtensions
you will notice that the Customer's name is stored within but that the name is a String attribute of Customer. This is accomplished using:
#XmlPath("personal-info/name/text()")
public String getName() {
return name;
}
I hope this helps,
Doug
Worth mentioning, if the content is a list of <entity/> instead of a single instance:
<root>
<wrapper>
<entity/>
<entity/>
...
</wrapper>
</root>
then you can use the #XmlElementWrapper annotation:
#XmlRootElement(name = "root")
public class Root {
#XmlElementWrapper(name = "wrapper")
#XmlElement(name = "entity")
private List<Entity> entity;
static class Entity { }
}
The whole point of JAXB or other mapping systems is to map the elements and their hierarchy to classes. In your example, you seem to want JAXB to somehow know that it can marshal entity into wrapper/entity and vice-versa without actually creating the class used for the wrapper mapping and the connection between root and entity. Which, as presented, is roughly equivalent to asking how to connect a car engine to the wheels without a driveshaft.
So, unless I am missing the point, the answer is no - neither JAXB or any other mapping program can do this. You can avoid creating classes by using something that does mapping purely dynamically (see Groovy, GPath for an example), but that avoids creating all classes, not just skipping one intermediate level in a hierarchy.
Related
I am developing a RESTful service using JAX-RS and JAXB. I have a Complain class, following is a striped down version of it:
#Entity
#Table(name = "complain")
#XmlRootElement
public class Complain implements Serializable {
private String title;
private String description;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "complainidComplain")
private Collection<Comment> commentCollection;
#XmlTransient
public Collection<Comment> getCommentCollection() {
return commentCollection;
}
}
Note: I have decorated getCommentCollection with #XmlTransient annotation, because I don't want to see comment when I'm looking for all the complains at #Path("/").
example.com/api/complain/
<complains>
<complain>
<title>Foo</title>
<description>Foo is foo</description>
</complain>
<complain>
<title>Bar </title>
<description>Bar is bar</description>
</complain>
</complains>
But when I'm looking for a specific Complain at #Path("/{id}"), I need the comments to appear in the XML output.
example.com/api/complain/1
<complain>
<title>Foo</title>
<description>Foo is foo</description>
<comments>
<comment> Yes, i agree </comment>
<comment> Lorem if foo </comment>
</comments>
</complain>
Since I have decorated getCommentCollection with #XmlTransient annotation I can't get comments when I'm looking for a specific Complain at #Path("/{id}"). How can I achieve this?
Annotating with #XmlTransient is a compile-time decission so you can't change it dynamically on runtime. As discussed at How to conditionally serialize with JAXB or Jackson you could use Jacksons JsonView or MOXy's external mapping-files.
If you don't want to change your Serializer you could map Complain to a limited Class like e.g. ComplainPreview which has only the properties title and description. You could also simply set commentCollection to null before returning it in your JAX-RS resource method.
Last (and maybe cleanest) solution: Fetch only the data you want to return from the Database. Therefore you need different queries for your two use cases. You could for instance use a Constructor Expression for the first one:
select new com.yourcompany.Complain(c.title, c.description) from Complain c
Don't forget to add the correspondent Constructor.
I'm working with a xml file that is generated and used in a .NET application.
I need to deserialize this file in Java and chose to use JAXB.
However, after trying to create the matching class I figured out one major difference.
When having a
#XmlRootElement
public class SomeClass{
List<NestedClass> classes;
}
I get the following structure:
<SomeClass>
...
<NestedClasses>
...
</NestedClasses>
<NestedClasses>
...
</NestedClasses>
</SomeClass>
As oppesed to the required existing structure:
<SomeClass>
...
<NestedClasses>
<NestedClass>
...
</NestedClass>
<NestedClass>
...
</NestedClass>
</NestedClasses>
</SomeClass>
Is there is a way to get my required structure without adding a class that will only contain the list of the nested class?
You will need to have a class that wraps the collection. To get the desired mapping, you can use the #XmlElementWrapper annotation to specify that a grouping element should be used. Then you can use the #XmlElement annotation to specify the name of the element that represents the items in the collection:
#XmlRootElement
public class SomeClass{
#XmlElementWrapper
#XmlElement(name="NestedClass")
List<NestedClass> classes;
}
For More Information
http://blog.bdoughan.com/2010/09/jaxb-collection-properties.html
Say, I have two classes:
#XmlRootElement
class A {
#XmlElement
String propertyOfA;
#XmlElement
B b;
}
class B {
#XmlElement
String propertyOfB;
}
JAXB returns an XML formatted in the according way:
<a>
<propertyOfA>valueA</propertyOfA>
<b>
<propertyOfB>valueB</propertyOfB>
</b>
</a>
My question is how to flatten the hierarchy in the XML? So that I have:
<a>
<propertyOfA>valueA</propertyOfA>
<propertyOfB>valueB</propertyOfB>
</a>
Can this be done with annotations?
At the moment I am thinking to create a kind of wrapper class for A, that would have fields built the way I want to see them in the XML. Is there a better way?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
You could use MOXy's #XmlPath extension to map this use case:
import java.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
class A {
#XmlElement
String propertyOfA;
#XmlPath(".")
B b;
}
For More Information
http://blog.bdoughan.com/2010/07/xpath-based-mapping.html
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2011/03/map-to-element-based-on-attribute-value.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html
It's been a while for me, but let me give it a crack:
#XmlRootElement
class A {
#XmlElement
String propertyOfA;
#XmlElement(name="propertyOfB")
B b;
}
#XmlType(name="")
class B {
#XmlValue
String propertyOfB;
}
Edit: disclaimer- I havn't compiled or tried this. But I believe it's how you do it.
Take a look to that question and the solution proposed: Spring RESTful client: root tag exception
Very helpful to solve this kind of problem.
An alternative approach (with standard JAXB) would be using #XmlJavaTypeAdapter. This way you could adapt the object hierarchy with the drawback of having to write the code that translates the object hierarchy into the adapted new class.
In your example however it wouldn't work as you would have to adapt class A which is your root. If however the hierarchy was deeper and you needed to make the adaptation one level lower than the root, then there wouldn't be a problem. A suggestion that might be useful is to write the code in the adapted entity, making it like a delegate to the object hierarchy, rather than the adapter, which would then be very thin.
I have an object graph that contains a cycle. How do I get JAXB to handle this? I tried using the #XmlTransient annotation in the child class but the JAXB marshaller still detects the cycle.
#Entity
#XmlRootElement
public class Contact {
#Id
private Long contactId;
#OneToMany(mappedBy = "contact")
private List<ContactAddress> addresses;
...
}
#Entity
#XmlRootElement
public class ContactAddress {
#Id
private Long contactAddressId;
#ManyToOne
#JoinColumn(name = "contact_id")
private Contact contact;
private String address;
...
}
This page in the "Unofficial JAXB Guide" offers three strategies for dealing with cycles. They are (in summary):
Mark one of the reference attributes that form the cycle as #XmlTransient.
Use #XmlID and #XmlIDREF so that the references are represented using XML ids arather than by containment.
Use the CycleRecoverable interface to deal with cycles programmatically.
The good thing about using JAXB is that it is a standard runtime with multiple implementations (just like JPA).
If you use EclipseLink JAXB (MOXy) then you have many extensions available to you for handling JPA entities including bi-directional relationships. This is done using the MOXy #XmlInverseReference annotation. It acts similar to #XmlTransient on the marshal and populates the target-to-source relationship on the unmarshal.
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/JPA/Relationships
#Entity
#XmlRootElement
public class Contact {
#Id
private Long contactId;
#OneToMany(mappedBy = "contact")
private List<ContactAddress> addresses;
...
}
#Entity
#XmlRootElement
public class ContactAddress {
#Id
private Long contactAddressId;
#ManyToOne
#JoinColumn(name = "contact_id")
#XmlInverseReference(mappedBy="addresses")
private Contact contact;
private String address;
...
}
Other extensions are available including support for composite keys & embedded key classes.
To specify the EcliseLink MOXy JAXB implementation you need to include a jaxb.properties file in with your model classes (i.e. Contract) with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
XMLTransient almost always works for cycles. It might be a possibility that you have XMLTransient on the field level but you have not specified XMLAccessorType to be XmlAccessType.Field. If you don't specify anything the default is XmlAccessType.Property - or your getters. I have experienced Jaxb picking xml elements from getters from a class that I missed the accessor type annotations on and still work perfectly fine.
just look at this tutorial : Mapping cyclic references to XML by jaxb
I use it an it works well :)
We can use XStream library as well, I tried it one project where JAXB was giving cyclic error but XStream handled it successfully
If a method of a JAX-RS application would return a domain object, the representation (say JSON) would contain all attributes of this object - right? But what if this object would contain "private" data, that shouldn't be exposed to the web?
And what is about the other direction from outside in: how could be prevented that private fields are overridden?
The only solution to this seems to create data transfer objects (dto).
To use an "automapper" wouldn't be the solution unless one can not specify what fields to map.
So, forces JAX-RS the developer to create DTOs? Or is there another solution?
For transparent marshalling and unmarshalling to and from XML of your entity, annotate it with JAXB annotations (a class can be annotated with both JPA and JAXB annotations and, this way, give an XML representation as well as be persisted in a database).
#Entity
#XmlRootElement
public class MyEntity implements Serializable {
#Id #GeneratedValue
private Long id;
....
}
In the above example I use only one JAXB annotation #XmlRootElement. Now, let's say that you don't want the id property in the serialized XML. Simply add the JAXB annotation #XmlTransient to it:
#Entity
#XmlRootElement
public class MyEntity implements Serializable {
#XmlTransient
#Id #GeneratedValue
private Long id;
....
}
So, no, there is no strict need for DTOs (and the boilerplate code to map them to and from entities).
I think it is better to say JAX-RS requires you to use representations.
My Foo domain object has no idea that it is being used in a RESTful manner. It only knows of Bar (another aggregate root) and whatever entities it can navigate from via that Bar. In fact, I also have a command-line interface to this application that doesn't use REST or even HTTP.
My RESTful interface wraps Foo/Bar in to representations that link to each other via URIs. I guess you can call these DTOs, but if you (like stated in other answers) just annotate your domain model with what is required to marshal and unmarshal them then I think you're coding yourself in to a corner that prohibits HATEOAS.
This is also apparent when you have a collection. If Foo->*Bar are you going to return all of the Bar items in their unmarshalled form? Why not just a URI and maybe some other minimal data,
e.g.
GET foo/fff
<foo>
<link rel="self" uri="uri="foo/fff" />
<bar uri="bar/abc123">
<status="Active" />
</bar>
<bar uri="bar/qqq">
<status="Inactive" />
</bar>
</foo>
If the client wants to know more about a given Bar, it can
GET bar/abc123
<bar>
<link rel="self" uri="bar/abc123" />
<foo uri="foo/fff" />
<status>Active</status>
<title>Some Bar</title>
...
</bar>
#XmlTransient (or a corresponding annotation) instructs the mappers/marshallers not to include the annotated property in the serialized output.