JAX-RS, with JAXB #XmlTransient - java

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.

Related

Springboot JPA entity is auto loading lazy join entities

I have an entity as
#Getter
#Setter
#Entity
#Table(name = "feature")
#JsonIgnoreProperties({"hibernateLazyInitializer", "handler"})
public class Feature {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
#Column(name = "name")
private String name;
#Column(name = "description")
private String description;
#OneToMany(mappedBy = "featureId", fetch = FetchType.LAZY)
private transient Collection<FeatureComponent> components;
}
While in its Repository(Dao) file, I have
public interface FeatureDao extends JpaRepository<Feature, Integer> {
#Query("SELECT e FROM Feature e")
public List<Feature> getAll();
#Query("SELECT e FROM Feature e LEFT JOIN e.components fc WHERE e.id= :id")
public Feature getWithDetail(#Param("id") Integer id);
}
When I'm calling featureDao.getAll(); it returns all features but including components list filled and because of that, my response it being too large to load on client-side.
I'm unable to understand why it is happening when I'm using Lazy fetch mode and didn't mentioned joining with components in my getAll method.
Please help to resolve that issue,
Thanks in advance.
Just like #spOOm already mentioned I also suspect this is the side effect of Jackson Feature entity serialization into JSON triggering the load of all the components.
That is why using DTOs instead of plain Entities is usually advisable when returning data via a Controller. With DTOs, you clearly define whatever you want to include in the response to the caller. You can even reorganize your model so that it fits better the needs of the clients. You decouple your inner model and the model your API consumers know, making it possible to rework your inner model and still keep the same public model. You could have the following DTO.
public class FeatureSimpleDto {
private Integer id;
private String name;
private String description;
}
Then, in your Controller or Service (here you can find different opinions) you would basically convert your Feature entity into a FeatureSimpleDto that would be returned by your Controller. Here you can use mapping libraries such as MapStruct or you can do it on your own (I usually tend to prefer doing it on my own, one less dependency to rely on).
Using Lombok may be a problem, depending on the relationship between tables, try to create getters manually in entity classes.
Thanks to everyone for providing workarounds... But every work item requires lots of changes which were not possible for me...
Luckily I found a solution that is working fine for me... Better to post here...
Step-1: Add dependency in pom.xml file
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-hibernate5</artifactId>
</dependency>
Step-2: Add a 'Bean' for Hibernate Module
We can add bean in any file having #Configuration annotation... Even, we can add in Springboot main application file(where we have main method).
#Bean
public Module datatypeHibernateModule() {
return new Hibernate5Module();
}
That's it, Happy Coding...

Field mapping with MapStruct by JsonProperty annotation

In my current project the names of the model class fields are German. The fields are all annotated with #JsonProperty for the English translation of the names. E.g. #JsonProperty(value = "operation"). Is there a way in the configuration that the mapping of the fields is done using the JsonProperty annotation?
Example:
public class Auftrag {
#JsonProperty(value = "orderType")
private String auftragsart;
...
}
public class OrderDto {
private String orderType;
}
MapStruct uses the Java Bean convention to detect the properties. This means that it looks in the getters and setters.
Out-of-the-box you cannot use the #JsonProperty. However, you can create your own AccessorNamingStrategy that will provide the properties based on #JsonProperty. The AccessorNamingStrategy gives you access to the Abstract syntax tree, which means you can look for fields in types, check their annotations and check their values.
Keep in mind that MapStruct will only ask to get the property for a method, so you would need to get the property name, then find the field in the type, then look for the #JsonProperty annotation and its value.
You can read more about the AccessorNamingStrategy here in the documentation.

Java Jersey use GET to return JSON that returns only some fields instead of all

Does naybody knows a way to use Jersey's GET method to return a JSON that returns only some fields of an entity instead of all?
Does anybody know a way to use Jersey's GET method to return a JSON that returns only some fields of an entity instead of all?
E.g. in the following class I want to receive (with POST) values for 'name' and for 'confidential', buy while returning (with GET) I only need 'name' value, not 'confidential'.
#Entity
#Table(name = "a")
#XmlRootElement
#JsonIgnoreProperties({"confifentialInfo"})
public class A extends B implements Serializable {
private String name;
#Basic(optional = false)
private String confifentialInfo;
// more fields, getters and setters
}
If you are using the JAXB approach, you can mark fields with #XmlTransient to omit them. If you are using POJO mapping or want to exclude fields only for some requests, you should construct the JSON with the low level JSON API.
If you are using Jackson, you can use the annotation #JsonIgnore for methods
Marker annotation similar to javax.xml.bind.annotation.XmlTransient
that indicates that the annotated method is to be ignored by
introspection-based serialization and deserialization functionality.
That is, it should not be consider a "getter", "setter" or "creator".
And #JsonIgnoreProperties for properties
Annotation that can be used to either suppress serialization of
properties (during serialization), or ignore processing of JSON
properties read (during deserialization).

Handling nested elements in JAXB

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.

Does JAX-RS require data transfer objects (DTO)?

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.

Categories

Resources