Strange Mapping Behaviour Jackson JSON - json

I've got a strange mapping Issue with Jackson on Android.
I've got a "Content" Class which should be used by the Jackson Mapper.
It looks like this:
public class content {
private String header;
private String subheader;
private String bodytext;
#JsonProperty("singleimage")
private String image;
#JsonProperty("uid")
private String id;
#JsonProperty("link")
private String article;
#JsonProperty("CType")
private String cType;
// Eclipse auto generated getters & setters
...
}
The corresponding JSON Object looks like this:
{
"header": "xyz",
"subheader": "abc",
"bodytext": "abc",
"singleimage": "abc",
"images": "abc.jpg",
"teaser_elements": "",
"uid": "13",
"link": "xyz.htm",
"CType": "row_header"
}
Now when I use the Jackson Maper to create instances of Content from a provided JSON all fields of the content class get populated correctly - all except "cType".
I already tried to move the #JsonProperty("CType") annotation to the setCType Method but still no effect.
I don't get any Exceptions while mapping the class or anything else and as it seems to me that all mappings pretty much do the same (mapping to String) im kinda buffled why it doesn't work wit the "CType".
Any suggestions what the problem might be are highly appreciated.

Related

Convert JSON properties with under_score to DTO with lowerCamel properties using Gson

I'm facing some difficulties while trying to convert JSON response which contains properties with under_score, to DTO with lowerCamelCase properties.
JSON for example:
{
"promoted_by": "",
"parent": "",
"caused_by": "jenkins",
"watch_list": "prod",
"u_automation": "deep",
"upon_reject": "cancel"
}
DTO for example:
#Data
public class TicketDTO {
private String promotedBy;
private String parent;
private String causedBy;
private String watchList;
private String uAutomation;
private String uponReject;
}
Mapper:
#Mapper(componentModel = "spring")
public interface ITicketMapper {
default TicketDTO toDTO(JsonObject ticket) {
Gson gson = new GsonBuilder()
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)
.create();
return gson.fromJson(incident, TicketDTO.class);
}
}
This example is not working of course, I would like to know if it's possible to do this conversion with Gson.
Appriciate your help.
You should use LOWER_CASE_WITH_UNDERSCORES
Using this naming policy with Gson will modify the Java Field name from its camel cased form to a lower case field name where each word is separated by an underscore (_).
Here's a few examples of the form "Java Field Name" ---> "JSON Field Name":
someFieldName ---> some_field_name
someFieldName ---> _some_field_name
aStringField ---> a_string_field
aURL ---> a_u_r_l
setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
The UPPER_CAMEL_CASE is used for different purpose
Using this naming policy with Gson will ensure that the first "letter" of the Java field name is capitalized when serialized to its JSON form.

Spring Rest: Mapping a property of a bean as nested JSON

My Spring REST controller needs to map an object parameter that looks like this:
{
"batchId": 43091,
"domain": "XX",
"code": "XXX",
"effectiveDate": "2020-02-13",
"status": "Y",
"result": [{"ruleName":"name",...]}]
}
I'm having trouble coming up with the DTO to convert this data into. What I have so far looks like this:
#Data
#NoArgsConstructor
#EqualsAndHashCode
public class ValidationResult {
private String result;
private String status;
private String batchId;
private String domain;
private String code;
private String effectiveDate;
}
But result, which contains the embedded JSON, is always null. I don't care about that JSON being mapped, as I'm storing it as a JSON type in the database (Postgresql). But what Java type do I need to declare it to be to get the controller to convert it? I tried making it a javax.json.JsonObject, but that failed.
What we always do with those json inputs is to map those to specific classes. Which means, in your case, result could be a class which itself contains the given fields "ruleName" and their types. Then your Validaton Result containts a private Result result. If naming conventions are quite right the used mapper will be able to convert and map the response to the class and its properties.

Spring Boot Jackson - Selectively serialize embedded object properties based on their depth

I have edited the question to provide more clarity.
My problem statement is how can I customize the way Jackson serializes an Entity that's sent in my REST Response, such that my JSON doesn't become too large / unreadable?
Consider I have the following Entities (or resources / models, etc)
public class Department
{
private Long id;
private String name;
private Employee head;
/***
* Other fields, getters and setters
*/
}
And another one, like this
public class Employee {
private Long id;
private String name;
private Department department;
/***
* Other fields, getters and setters
*/
}
I have a REST API that gets an Employee by his/her ID, and here's the response when I call that
GET /api/employees/2
{
"id":"2",
"name":"John Doe",
"department":{
"id":3,
"name":"Product Support",
"head":{
"id":1,
"name":"The Chairman",
"department":{
"id":1,
"name":"Executive",
"head":null
}
}
}
}
The response, as you can see, is large (and can get really large depending on the data model). I want to stop the serialization from going deep into nested objects.
My preferrable JSON Response would be:
GET /api/employees/2
{
"id":"2",
"name":"John Doe",
"department":{
"id":3,
"name":"Product Support",
}
}
I already am aware that I can use the #JsonIgnore annotation on Department.head, like this:
public class Department
{
private Long id;
private String name;
#JsonIgnore
private Employee head;
/***
* Other fields, getters and setters
*/
}
But, this will skip serializing the head property permanently. For instance, see the below REST API call, post adding #JsonIgnore
GET /api/departments/3
{
"id":3,
"name":"Product Support",
}
// Here, I want the Full serialized form of the Department Object
So, as you can see, here's the question: I want the Department object to be serialized fully, when I call GET /api/departments/3. But, I want it to skip the head property when I call GET /api/employees/2. How do I achieve this in Jackson, when used in Spring Boot?
I also came across a library called Squiggly that uses a GraphQL like query language for the API responses, but I would like to know if I can do without having to learn a new library.
Thanks very much
Edit After Abbin Varghese's Answer
I changed my Employee model to the one below:
public class Employee {
private Long id;
private String name;
#JsonIgnoreProperties({"head"})
private Department department;
/***
* Other fields, getters and setters
*/
}
Upon serialization, this gave me the following JSON output:
{
"id":"2",
"name":"John Doe",
"department":{
"id":3,
"name":"Product Support",
}
}
The pro here, is that it solves my problem, without having to write a separate DTO class for my models.
The con however, is this: In this case, I'm trying to skip serialization only for the head property, so it makes sense to include this in the #JsonIgnoreProperties annotation. What if the list of properties to skip is longer than the list of properties to serialize? For example, if my Department as 15 properties, and I wish to serialize only 3 of them, then it becomes difficult to include the 12 properties to skip in the #JsonIgnoreProperties annotation.
Is there an annotation that does the opposite (Include only these fields, etc.)??
JsonProperty.Access.WRITE_ONLY is a good way to avoid elements.
For example..
#JsonProperty(access = JsonProperty.Access.WRITE_ONLY)
#ManyToOne
#JoinColumn(name = "MODIFIED_BY")
private User lastUpdatedBy;

Solution for Generic in Go

I want to make a useful library for JSON responses. In Java I've this already. I started now new with Go and have no idea how to transform my Java code. I've read that Go doesn't have anything like generics, but how can I solve my problem?
I'm talking about the following part of code:
#Data
public class ServiceResult<T extends Serializable> implements Serializable {
private ServiceResultStatus status;
private String type;
private T content;
private String hash;
private String destination;
private HashMap<String, Metadata> metadata = new HashMap<>();
...
The idea of service-result is to provide an structural pattern for RESTful web services. If you need more information, here is the link to my repo on Github: https://github.com/Viascom/service-result
A service-result looks at the end like this:
{
"status": "successful",
"type": "ch.viascom.example.models.response.GetTasksResponse",
"content": [
{
"id": "3e99c7fb-0ed7-11e7-a7a5-0050569c3e5a",
"name": "Example Task"
}
],
"hash": "7bf9c04d1e9f8fe7995e4b8beeac1a4c830e7ea",
"destination": "ch.viascom.example.handler.TaskHandler",
"metadata": {
}
}
You can add the json-mapping directly to the structure definition and use the encoder, decoder to marshal and unmarshal it. It's all built in and easier than in other languages, imho.
type ServiceResponse struct {
Value string`json:"nameInJsonResponse"`
}
here is a good example from the playground: https://play.golang.org/p/4L2wMVv7tW
For your particular case it should be something like this:
type ServiceResult struct {
Status ServiceResultStatus`json:"status"`
Type string`json:"type"`
Hash string`json:"hash"`
Destination string`json:"destination"`
Metadata map[string]Metadata metadata`json:"metadata"`
}
type ExplizitServiceResult struct {
ServiceResult
Content SomeStruct`json:"content"`
}
https://play.golang.org/p/FFfiq6LxVt
If you don't want to derive every user struct from the ServiceResult you can define the content as interface{} so every struct can be inserted. I've updated my example for this. Maybe this is the easiest solution to your problem.
https://play.golang.org/p/LNgreqrnnw

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
}