Pattern to map JPA Objects to DTO for Conversion to JSON - json

I have a somewhat philosophical question relating to mapping JPA Objects to JSON Strings. Of course there is no necessity for the source object to be a persistent object - it is just that that is my situation.
I have a collection of objects that are managed by Eclipse Link. I need to turn some of these objects into JSON Strings, however the mapping is not one-to-one. I am convinced that the conversion should be loosely coupled so as to isolate the JSON objects from changes in the underlying entities.
I am planning to have the JPA entity as such:
#Entity
#Table(name = "AbnormalFlags")
public class AbnormalFlag implements java.io.Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(name = "Code", unique = false, nullable = false)
private String code;
#Column(name = "Description", unique = false, nullable = false)
private String description;
// Getters and setters
}
and the equivalent object to be converted to JSON
public class AbnormalFlagDTO implements java.io.Serializable {
private String code;
private String description;
private Boolean disabled;
// Getters and setters
}
Is there an elegant pattern or methodology I can use to facilitate this process for several types of objects.
Thanks in anticipation

My answer: no, and also you should generally extend DTOs with care (when reusing existing DTOs). But you could use a Map<String, Object> as a DTO (if you do not use the same DTO to read the data back). Besides you could create an APT (annotation processor tool) that generates the code for DTOs from your entities and then you simply modify them.

This is a perfect use case for Blaze-Persistence Entity Views as you will most probably also want to keep an eye on the performance of the query used for fetching the data.
I created the library to allow easy mapping between JPA models and custom interface defined models. The idea is that you define your target structure the way you like and map attributes(getters) via JPQL expressions to the entity model. Since the attribute name is used as default mapping, you mostly don't need explicit mappings as 80% of the use cases is to have DTOs that are a subset of the entity model.
A mapping for your model could look as simple as the following
#EntityView(AbnormalFlag.class)
interface AbnormalFlagDTO extends Serializable {
String getCode();
String getDescription();
Boolean getDisabled();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
AbnormalFlagDTO dto = entityViewManager.find(entityManager, AbnormalFlagDTO.class, id);
The serialization of the entity view to JSON will work as expected. If you also want to deserialize objects, you will have to construct the object first and also add setters to the interface.

Related

Fetch related entities as Base Type

I'm currently trying to setup a database – using Java only. Given this simple class that might appear in the average social network app:
#Entity
class User {
#Id
private String email;
private String name;
private String otherInfo;
#ManyToMany
private List<User> contacts;
}
When the user logs in, he should receive the basic information and the list of contacts with their basic info, but not their contacts. To reduce the amount of boiler-plate code, I want to use a standard solution like Gson. However, even with lazy fetch the whole user is loaded on gson.toJson(user).
Therefore I thought of extracting the basic infos into a base class BasicUser and changing the contacts to List<BasicUser>. Now I only need to somehow circumwent the discriminator column when I fetch the contacts – of course they are all saved as complete users on the server. Unfortunately, I don't know how to archieve that. Any ideas?
If you need to get only part of the entity you can use projections. In your case it can be, for example, like this:
public interface BaseUser {
String getEmail();
String getName();
String getOtherInfo();
}
public interface UserRepo extends JpaRepository <User, String> {
List<BaseUser> findAllBy();
}
Using Jackson for serialization, the problem can be solved without writing custom serialization code. BasicUser contains the getters of the attributes, I want to serialize:
public interface BasicUser {
String getEmail();
String getFirstName();
String getLastName();
}
With a single annotation the contacts attribute is interpreted as a list of BasicUsers:
#Entity
public class User implements BasicUser {
#Id
private String email;
private String firstName;
private String lastName;
#ManyToMany
#JsonSerialize(contentAs = BasicUser.class)
private List<User> contacts = new ArrayList<>();
// ... implemented getters
}
You shouldn't have to modify your domain model just to accomodate a serialization library.
If you only want certain fields of a collection to be exposed to JSON, you could use Jackson with #JsonView (see here: How to serialize using #Jsonview with nested objects) not sure if Gson provides a similar feature as I have never used it extensively.

REST: how to serialize a java object to JSON in a "shallow" way?

Suppose I have the following JPA entities:
#Entity
public class Inner {
#Id private Long id;
private String name;
// getters/setters
}
#Entity
public class Outer {
#Id private Long id;
private String name;
#ManyToOne private Inner inner;
// getters/setters
}
Both Spring and java EE have REST implementations with default serializers which will marshall the entities to/from JSON without further coding. But when converting Outer to JSON, both Spring and EE nest a full copy of Inner within it:
// Outer
{
"id": "1234",
"name": "MyOuterName",
"inner": {
"id": "4321",
"name": "MyInnerName"
}
}
This is correct behavior but problematic for my web services, since the object graphs can get deep/complex and can contain circular references. Is there any way to configure the supplied marshaller to marshall the POJOs/entities in a "shallow" way instead without having to create a custom JSON serializer for each one? One custom serializer that works on all entities would be fine. I'd ideally like something like this:
// Outer
{
"id": "1234",
"name": "MyOuterName",
"innerId": "4321"
}
I'd also like it to "unmarshall" the JSON back into the equivalent java object. Bonus kudos if the solution works with both Spring and java EE. Thanks!
After many problems I give reason to Cássio Mazzochi Molin saying that "the use of entities persistence in your REST API can not be a good idea"
I would do that the business layer transform persistence entities to DTO.
You can do this very easily with libraries like mapstruct
If you still want to continue with this bad practice you can use jackson and customize your jackson mapper
To unscramble complex object graphs using jaxb #XmlID and #XmlIDREF is made for.
public class JSONTestCase {
#XmlRootElement
public static final class Entity {
private String id;
private String someInfo;
private DetailEntity detail;
#XmlIDREF
private DetailEntity detailAgain;
public Entity(String id, String someInfo, DetailEntity detail) {
this.id = id;
this.someInfo = someInfo;
this.detail = detail;
this.detailAgain = detail;
}
// default constructor, getters, setters
}
public static final class DetailEntity {
#XmlID
private String id;
private String someDetailInfo;
// constructors, getters, setters
}
#Test
public void testMarshalling() throws JAXBException {
Entity e = new Entity( "42", "info", new DetailEntity("47","detailInfo") );
JAXBContext context = org.eclipse.persistence.jaxb.JAXBContextFactory.createContext(new Class[]{Entity.class}, null);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.setProperty(MarshallerProperties.MEDIA_TYPE, "application/json");
m.setProperty(MarshallerProperties.JSON_INCLUDE_ROOT, false);
m.marshal(e, System.out);
}
}
This will result in the following json-fragment
{
"detailAgain" : "47",
"detail" : {
"id" : "47",
"someDetailInfo" : "detailInfo"
},
"id" : "42",
"someInfo" : "info"
}
Unmarshalling of this json will ensure that detail and detailAgain are the same instances.
The two annotations are part of jaxb, so it will work in Spring as well as in java EE. Marshalling to json is not part of the standard, so i use moxy in the example.
Update
Explicitly using moxy is not neccessary in a JAX-RS Resource. The following snipped perfectly runs on a java-EE-7 container (glassfish 4.1.1) and results in the above json-fragment:
#Stateless
#Path("/entities")
public class EntityResource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Entity getEntity() {
return new Entity( "42", "info", new DetailEntity("47","detailInfo") );
}
}
I had the same problem and ended up using jackson annotations on my Entities to control the serialization:
What you need is #JsonIdentityReference(alwaysAsId=true) to instruct the bean serializer that this reference should be only an ID. You can see an example on my repo:
https://github.com/sashokbg/company-rest-service/blob/master/src/main/java/bg/alexander/model/Order.java
#OneToMany(mappedBy="order", fetch=FetchType.EAGER)
#JsonIdentityReference(alwaysAsId=true) // otherwise first ref as POJO, others as id
private Set<OrderDetail> orderDetails;
If you want a full control of how your entities are represented as JSON, you can use JsonView to define which field is serialized related to your view.
#JsonView(Views.Public.class)
public int id;
#JsonView(Views.Public.class)
public String itemName;
#JsonView(Views.Internal.class)
public String ownerName;
http://www.baeldung.com/jackson-json-view-annotation
Cheers !
for this problem There are two solutions.
1-using jackson json view
2- Createing two mapping classe for innner entity. one of them includes custom fields and another one includes all fields ...
i think jackson json view is better solution ...
Go through the FLEXJSON library to smartly include/exclude nested class hierarchy while serializing Java objects.
Examples for flexjson.JSONSerializer presented here
You can detach the JPA entity before serialization, if you use lazyloading it's avoid to load sub objects.
Another way, but is depend of the JSON serializer API, you can use "transient" or specifics annotation.
Why does JPA have a #Transient annotation?
A bad way is to use tool like dozer to copy JPA object in another class with only the properties need for json (but it works... little overhead of memory, CPU and time...)
#Entity
public class Outer {
#Id private Long id;
private String name;
#ManyToOne private Inner inner;
//load manually inner.id
private final Long innerId;
// getters/setters
}

Serializing JPA entities to JSON using Jackson

Question regarding combination of Jackson/JPA
If there are about 20 entities in current application and I have add Jackson dependency in POM, does it mean all entities are by default ready to convert to JSON object? I saw a sample project seems only class annotated as #JsonIgnored is skipped by JSON. If so, then how can this happen, what is behind such mechanism? how JACKSON handle those entities which don't have any Jackson annotation, by default ignored or not? I've been looking for resources online but not much luck.
If only one of the 20 entities need to be mapped to JSON object, does it mean I have to add #JsonIgnore to all other 19 entities? If not, how Jackson differentiate with entity to work on?
Thanks.
Jackson and JPA don't have anything to do with each other. Jackson is a JSON parsing library and JPA is a persistence framework. Jackson can serialize almost any object - the only requirement being that the object have some kind of recognizable properties (Javabean type properties, or bare fields annotated with #JsonProperty. There is an additional requirement for deserialization, that the target type have a default (no-arg) constructor. So, for example, this is an object that Jackson can serialize:
// Class with a single Javabean property, "name"
class Person {
private String name;
public String getName() { return name ; }
public String setName(String name) { this.name = name ; }
}
And here is another:
// Class with a single field annotated with #JsonProperty
class Account {
#JsonProperty("accountNumber")
private String accountNumber;
}
And here is yet another:
#Entity
public class User {
#Id
private Long id;
#Basic
private String userName;
#Basic
#JsonIgnore
private String password;
#Basic
#JsonIgnore
private Address address;
// Constructors, getters, setters
}
The last example shows a JPA entity class - as far as Jackson is concerned it can be serialized just like any other type. But, take note of its fields: when this object is serialized into JSON two of the fields will not be included - 'password' and 'address'. This is because they have been annotated with #JsonIgnore. The #JsonIgnore annotation allows a developer to say 'Hey, its ok to serialize this object, but when you do so don't include these fields in the output'. This exclusion only occurs for the fields of this object, so for example, if you included an Address field in another class, but did not mark the field as ignorable, it would be serialized.
To prevent serialization of a type in all cases, regardless of context, use the #JsonIgnoreType annotation. When used on a type it basically means 'I dont care where this type is used, never serialize it'.
No, you don't need to add #JsonIgnore on every class and if you had tried you would have gotten a compile error, since you can't put it there. Jackson will only work on objects you give to it, it's no magic.
The Jackson documentation is easily found online, such at its project page on github or on the codehaus website.

Spring MVC, REST, Jackson, Dojo dojox.data.jsonRestStore, how to make dojo-style references?

Pretty simple question, hard to find an answer:
I want to Serialize in JSON my POJO JPA entities with references being Dojo-like to use it with dojox.data.JsonRestStore.
The server part is made with Spring MVC and HttpConverters to make it a RESTfull web-app. I'm using JacksonJson to convert JPA entities to JSON.
As a lot of people have, I do have problems with multiple references. #JsonBackReference and #JsonManagedReference do not do the trick!
Considering this basic example:
public class A {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#Column(nullable=false)
private String field;
#OneToMany(mappedBy = "b")
private List<B> bs;
}
public class B {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#ManyToOne
private A a;
}
With the basic Jackson Json converter you obtain something like this (considering you have put the #JsonBackReference and #JsonManagedReference):
{ id:1, fieldB:"bbbbb", a: { id:1, fieldA: "aaaaaa" }}
In a concrete application, having the list of bs from the A objects is pointless in most cases. But having knowing what kind of A object is in the B.a field is important (at least to me).
Now, the problem lies in the references which are copied and you can end up having some serious big JSON with not much data in it.
The Dojo Framework provides a reference standard explained in here : http://www.sitepen.com/blog/2008/06/17/json-referencing-in-dojo/ and
http://dojotoolkit.org/reference-guide/dojox/data/JsonRestStore.html.
So what I'm searching is a way to define this as the following:
{ id:1, fieldB:"bbbbb", a: { $ref: "getA/1"}}
First problem: Jackson obviously can't know what url you will use for the Reference.
To resolve that problem I made very simple interface like this:
public interface EntityWithId {
public Long getId();
public void setId(Long id);
}
This interface in then implemented by all my entities and I made this very very simple JsonSerializer:
public class EntityIdSerializer extends JsonSerializer<EntityWithId> {
#Override
public void serialize(EntityWithId value, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
jgen.writeStartObject();
jgen.writeStringField("$ref", "db/" + value.getClass().getSimpleName() + "/" + value.getId().toString());
jgen.writeEndObject();
}
}
With those two I got the desired JSON, adding #JsonSerialize(using = EntityIdSerializer.class) to the #ManyToOne fields.
Is there no more standard approach? The Dojo dojox.data.JsonRestStore sounds really promising as you can combine it with lots of Dijits widgets, but is it really a nice thing to do and try? Won't my REST app be to much Dojo-restrictive?
Thanks for your answers!
Dojo approach sounds like it requires dealing with a complete logical tree, to be able to use location-based references. This will not work well with Jackson, which supports fully incremental data-binding, i.e. only subset of the logical being available at the point where data is read or written.
So Jackson does not support it by default; nor is that approach considered much of a standard in general (AFAIK). At least I havent seen it supported by Java libraries.

Spring MVC and json serialization

I am developing web application with spring mvc and Data sent to client in json format.
I want to have some views of same model object thus i can return only needed data ,not more.Jackson library #JsonIgnore , #JsonIgnoreProperties not suit this .Jackson library have also #JsonView and #JsonFilter annotations but they didnt help too.How can handle this problem.For example ,i will need possibleTarget list in some pages of UI and sometimes dont need.This is the same question but answer not help me
#Entity
public class Warrant implements Serializable {
#Column
String name;
#JsonIgnore
#ManyToOne
private User owner;
#Column
private String value;
#OneToMany(mappedBy = "warrant", targetEntity = com.endersys.lims.model.Target.class)
private List<Target> possibleTargets;
.....
}
You're mixing application layers. Don't send entities from your persistence layer to the view. Use Transfer Objects, that way you can easily control what you show the world.
You might want to use a framework like Dozer to automate data transfer between layers.