Does a pattern exist for serializing Java objects to JSON? - java

This question is not concerning the exact specifics of how to serialize a Java object to a JSON representation, but rather a scalable and testable pattern for serializing Java objects to JSON. The system in which I'm maintaining has the notion of varying levels of granularity with regards to serialization of objects. For example, the system has a concept of a Project. A Project has the following fields:
Name
Description
Owner
List of tasks
Change history
Other metadata
When serializing a list of Projects, it's useful to only return the "summary" information:
Name
Description
Owner
Omitting the more detailed stuff. However, when request a single Project, a "detailed" view is returned which includes everything. Most objects in the system have this notion of a summary and a detail view, but I'm finding that in most cases, I'm either returning too much or too little information.
To handle which attributes are returned for which view, I've simply annotated the class, and described a summary and a detail view:
#Json(summary = { "name", "description", "owner" },
detail = { "name", "description", "owner", "tasks", "changes", ... }
class Project {
private String name;
...
}
This works decently, but as I mentioned above, I find in most cases, I'm either returning too much or too little. I would be interested to see what kind of patterns exist out there for a flexible approach to getting the data I need. Am I doing it wrong if I'm finding that I'm needing to return different representations of my data? Should I pick a set number of object representations and stick with that? Thanks for your help.

You could use subclassing with an automatic serialisation framework. For example using JAXB (which supports both JSON and XML):
class DetailSummary {
public #XmlElement String name;
public #XmlElement String description;
public #XmlElement String owner;
}
class Detail extends DetailSummary {
public #XmlElement List<Task> tasks;
...
}
This approach allows multiple levels of detail but forces you to use your classes as simple records.

Related

Is it a good practice to create many DTO for a model?

Assuming I have a class User with many fields:
public class User {
public Integer id;
public String name;
public String username;
public Integer age;
public Address address;
public String phoneNumber;
public String email;
}
But I will not always need all User attributes in frontend. Each screen needs only some of User's fields. Is it a good practice to make DTO classes for each screen, since they access different attributes? Like this:
class UserToScreenADTO implements Serializable {
public String name;
public String email;
}
class UserToScreenBDTO implements Serializable {
public String phoneNumber;
public Address address;
}
class UserToScreenCDTO implements Serializable {
public Integer id;
public String username;
public String email;
}
I would create just one DTO class but e.g. pass to its constructor
the list of the fields which I want to be pulled and set by the backend.
All other fields will be null.
The list of fields will be passed in by the front-end.
I find this approach pretty flexible/dynamic.
It also avoids multiple classes to maintain.
I don't know if this approach matches any best practices or enterprise patterns
but creating multiple DTO classes definitely sounds worse.
Using "just" one DTO or the entity directly comes with a high cost that you usually only pay later, so I would recommend anyone to create a DTO per use case just like you did here.
Here are some of the reasons/costs for this:
If the user of the API sees accessors for state that isn't loaded this will trigger lazy loading which will either result in bad performance or lazy initialization exceptions. If objects are passed through a session, you might lose the context how the object came to be, so you might not always be able to tell which state is loaded.
It might be inefficient to load all data all the time. If you have some text columns that contain lots of data this has to be transferred over the wire and materialized as Java Objects etc. If you don't use the data, it's just pointless to load it at all. One might say this is negligible, but it depends on your use case. The worst that can happen? The DBMS does a full table scan or a less efficient index scan rather than index only scan because you instruct the DBMS to load the value for a column.
Not all the state that you want to provide for a client should be in the relational representation. If you do aggregations or use expressions for e.g. concatenating columns together, you need a DTO.
Having said that, this is a perfect use case for Blaze-Persistence Entity Views.
I created the library to allow easy mapping between JPA models and custom interface or abstract class defined models, something like Spring Data Projections on steroids. The idea is that you define your target structure(domain model) the way you like and map attributes(getters) via JPQL expressions to the entity model.
A DTO model for your use case could look like the following with Blaze-Persistence Entity-Views:
#EntityView(User.class)
public interface UserToScreenADTO extends Serializable {
String getName();
String getEmail();
}
#EntityView(User.class)
public interface UserToScreenBDTO extends Serializable {
String getPhoneNumber();
Address getAddress();
}
#EntityView(User.class)
public interface UserToScreenCDTO extends Serializable {
Integer getId();
String getUsername();
String getEmail();
}
Querying is a matter of applying the entity view to a query, the simplest being just a query by id.
UserToScreenADTO u = entityViewManager.find(entityManager, UserToScreenADTO.class, id);
The Spring Data integration allows you to use it almost like Spring Data Projections: https://persistence.blazebit.com/documentation/entity-view/manual/en_US/index.html#spring-data-features
Since OP said that the system is used from the same frontend and in the same context, I would consider it bad practice and not recommend using different DTOs.
Reasoning:
Modern frontends normally manage a store of all entites received by the backend. So the frontend can look up entities in the store and - depending on caching policies - load them from the store rather than requesting them from the server. Thus, instead of fetching users part-by-part, the user is transmitted once. This can be further improved by using ETags. While the usage of Etags will hardly improve latency, it can improve network load since the response to a matching ETag is a 304/Not Modified without a body (!) rather than a 200/OK with body. While ETags can be used with many Dto-Objects, more (partial) updates might occur. If, for example, the email and the phone number of a user changes, and the frontend first requests the UserToScreenADTO, it would get a response body that - among other things - contains the new email. When it then later requests a UserToScreenBDTO, it would - again - receive a response body containing the new phone number. With only one DTO, the frontend will receive one updated representation on the first request, and all successive request (made with the matching ETag) will result in a 304/Not Modified.
Furthermore, more classes normally mean higher complexity. Thus, I would recommend to keep the number of classes reasonably small. If using an ETag is not wanted and/or the frontend does not keep a store of server-sent entities, I would recommend the approach described in peter petrov's answer.
The representation should only change if the context changes. If the representations differ drastically between, for example, a user-frontend and an admin-frontend, then different DTOs may be justified.

convert java domain model from domain A to domain B

I have a domain model A which I want to transform into another domain model B. So for each model element I need to convert it into one or a number of elements of B.
Domain A looks very simplified like:
public class Model
{
public List<ModelElement> elements;
}
public class ModelElement
{
public SubElement subElement;
}
public class SubElement
{
public String someData;
}
Domain B looks like
public class Layout
{
public List<Layer> layers;
}
public class Layer
{
public LayerData layerData;
}
public class LayerData
{
public int layerNumber;
public String name;
}
This is really simplified, my models are a bit more complex, but for explaining I think it is enough.
So my question is, what is a good approach for the converter.
I thought writing a single class, which traverses through the model and converts each element. By the end I have a huge converter class, which is not so nice.
My other approach was to build a factory, which gives for each element of Domain A a specific converter. Each converter can then call the factory to get the converter for sub elements. Unfortunately I need for some element conversions additional data. So to use it in some converters I must pass them through all the upper converters, which does not sound very nice as well.
What would be a good way to do it?
Thanks for help
Simon
If your data modle is hierarchical and finite I'd go with the first approach, but divide its responsibilities down to several classes. Have the main class publishing the data needed to convert. Then it calls a converter class for the root (Model/Layout) which converts and calls sub-converters (ModelElement/Layer level) and so on. The trick is to always pass a reference to the main class, which will work like an envelope or data store to the converters. By doing so, you'll get a nice, decoupled design with single responsiblites: providing data, converting a single class and so on.
This is only a sketch of the design I'd go. It's the best I can draw given the information. You may want to adapt it and maybe add some abstraction (e.g. interfaces with reduced data publishing for the envelope class).
You may want to look at DOZER. The lib will allow wildcard transformation of fields (if they share the same name) and also permit custom converter.

Hibernate and subclassing data classes in Java

Is there an easy way to do the following, using the Play! framework and hibernate?
I have a class Article with generic data like pubDate, author etc. etc.
In the class there are two fields, title and content, which needs however be provided in different languages. All the other data, inclusing the id should be the same.
The server side of the system will select according to the settings of the client which title/content to push out, either the default language or the language of preference when available. Beacuse of the synchronisation it is important to keep the article id the same for all linked languages.
Currently I have the content and the title in the class, and am wondering if I should either subclass the baseclass which has all the basic info and add the content/title that way, our leave the content/title of the default language in the baseclass and optionally add the content/title of additinoal languages as an seperate class (and on pushing it to the client replace it the content transciently in the baseclass if required).
What would be the best way to approach this problem?
I wouldn't subclass, because language preference is a rendering issue. There's no different behavior by Article just because the content is in a different language.
I'd have the Article class include title, content, and language. The primary key would now be article id and language. When a user asked for a particular title I'd query for it using the article id and either their language preference or the default if none was provided.
I would implement language specific data in a separate table if it is not easy to use i18n such this cases.
You could have Article and ArticleDetail models. In this model you have one Article and many language instances of this Article.
#Entity
public class Article extends Model {
private Author author;
private Date pubDate;
...
}
#Entity
public class ArticleDetail extends Model {
#MayToOne
private Article
private String languageCode;
private String title;
private String content;
...
}
So if you want to select a content just call ArticeDetail.find("article.id=? and langCode=?", articleId, langCode)

Injecting fields into Java JPA fields

I'm no pro with Java, so I need a little help. I'm using the Play Framework.
I have an Entity class which extends GenericModel with fields like the following:
#Column(name = "description")
private String description;
I want to add an additional field using a getter, let's call it getToString, which basically contains a read only string with the string representation of the entity.
I need this because the object is getting sent as a JSON response, and my JavaScript will read this field, and display it where for example the entity needs to be represented as a string.
How do I go about doing this?
I'm no expert on the Play framework, but probably you should have a look at the #Transient annotation.
Fields (and getters/setters if you are using JPA property access) marked with #Transient will be ignored by JPA, but usually be considered by other frameworks.
The problem I'm having was a side effect of using GsonBuilder. The builder doesn't appear to be parsing getters and setters, unless the source of the library is modified, which I'm not willing to do.
For what I understand (please correct me if I'm wrong) you want a read-only method that will return a string representation (JSon format) of the entity.
You could just override the default toString method:
#Override
public String toString() {
return "your_json_string";
}
and call it when needed

jackson deserialization into pojos

I'm trying to deserialize JSON Object coming from an application I can't control. Here my JSON :
{"assembly":
{"name":"mm9",
"id":32,
"chromosomes":[
{"chromosome":
{"name":"MT"}
}]}}
My Pojos, are
class Assembly{
private String name;
private int id;
private ArrayList<Chromosome> chromosomes;
// getters & setters
}
class Chromosome {
private String name;
//getter/setters
}
But it's not working because of the extra fields "assembly" & "chromosome", so with a JSON like :
{"name":"mm9",
"id":32,
"chromosomes":[
{"name":"MT"}
] }}
it simply working.
Is there a way to modify configuration or something to achieve this without create more complex POJOS?
The problem is that in the first JSON snippet, chromosomes is a dictionary (Map), of which one of the entries (chromosome) happens to correspond to your Chromosome object.
A more accurate direct mapping to a Java class would be
class Assembly{
...
private Map<String, Chromosome> chromosomes;
}
Since you mention you can't control the format of the source JSON, you may want to look into using custom deserializers, or perhaps using the streaming support from Jackson rather than ObjectMapper for direct mapping, if you aren't happy changing your POJOs in this way.
By the way, it is best to refer to collections by their interface type (List) rather than a concrete type (ArrayList). It is very unlikely that code that refers to this class truly cares or needs to know that it is using an ArrayList, referring to just the List interface instead makes it a lot easier to swap other implementations in if needed (as a general principle).

Categories

Resources