I have been using Jackson (which works great BTW) for all the json "tree" that I am traversing until I get to the deepest json level where unfortunately the json properties are "dynamic" such as the below so it does not make sense to create objects for those...
"values": [
{
"duration": 0.20669677067008357
},
{
"weight": 0.013746673955838557
}
]
The issue is that "duration" and "weight" are dynamic so I was hoping to use List<String[]> for 'values' but I don't think that it is possible. For example, the next call could have "duration", "weight", and "marketValue" or 10 other properties.
Any suggestions on how to approach this problem?
I actually found a solution for those interested:
This article/how to was very helpful in understanding the jackson data-binding flexibility:
http://www.studytrails.com/java/json/java-jackson-Annotations-Dynamic-Beans.jsp
Particularly, I chose to use the annotation #JsonAnySetter such as this on my POJO:
private String name;
private Object value;
#JsonAnySetter
public void set(String name, Object value) {
this.name = name;
this.value = value;
}
I then opted to place those name/value pairs into a Map<String, Object> for easy retrieval... Works great!
Related
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
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
}
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.
I'm getting a pretty strange error when marshalling my object to json. My object is annotated like this.
My class:
#XmlRootElement(name = "myobject")
public class MyObject {
private List<String> contactPersonsForMyObject;
#javax.xml.bind.annotation.XmlElement()
public List<String> getContactPersonsForMyObject() {
return contactPersonsForMyObject;
}
public void setContactPersonsForMyObject(List<String> contactPersonsForMyObject) {
this.contactPersonsForMyObject = contactPersonsForMyObject;
}
}
Everything works fine except for that if the List contactPersonsForMyObject contains only one value it get's marshalled to a string which ofcourse creates problems since the application consuming this expects a list.
The marshalled object:
[
{
"myobject": {
"somethingcool": "amazing",
"contactPersonsForMyObject": [
"test.test#gmail.com",
"test#test.se"
],
"myObjectId": "c85e48730501bfae41e67714c6131b7d"
}
},
{
"myobject": {
"somethingcool": "cool",
"contactPersonsForMyObject":"test#test2.se",
"myObjectId": "c85e48730501bfae41e67714cqwerty"
}
}
]
Why does this happen and how do I force it to create a list with one value?
Try using Jackson to handle processing your objects into JSON, it solved the same array problem for me in the past. If you are using RESTEasy (version 1.2 GA) with Maven, this link should help you get things setup to use Jackson to serialize objects to JSON.
This article also has some useful information for integrating Jackson with RESTEasy. Hope this helps!
I have a JSON object which I don't have control of and want to map it to a Java object which is pre-created.
There is one attribute in the JSON object which can be a URL or it could be a JSONArray.
Class SomeClass {
private URL items;
public URL getURL() {
return items;
}
public void setURL(URL url) {
this.items = url;
}
}
Below is the JSON:
Case A:
{
...
items: http://someurl.abc.com/linktoitems,
...
}
OR
Case B
{
...
items: [
{ "id": id1, "name": name1 },
{ "id": id2, "name": name2 }
]
...
}
If i create the POJO to map for Case A, Case B fails and vice versa. In short, is there a way to map the JSON attribute to the POJO field with different data types? In that case I will create two separate fields in the POJO named,
private URL itemLink;
private Item[] itemList;
It depends on exact details, but if what you are asking is if it is possible to map either JSON String or JSON array into a Java property, yes this can be done.
Obvious way would be to define a custom deserializer which handles both kinds of JSON input.
But it is also possible to define Java type in such a way that it can be constructed both by setting properties (which works from JSON Object) and have a single-String-arg constructor or static single-String-arg factory method marked with #JsonCreator.
Yet another possibility is to use an intermediate type that can deserialized from any JSON: both java.lang.Object and JsonNode ("JSON tree") instances can be created from any JSON. From this value you would need to do manual conversion; most likely in setter, like so:
public void setItems(JsonNode treeRoot) { .... }
What will not work, however, is defining two properties with the same name.
One thing I don't quite follow is how you would convert from List to URL though. So maybe you actually do need two separate internal fields; and setter would just assign to one of those (and getter would return value of just one).