Shared references with json - json

is it possible to make use of the concept of shared references with JSON as output mode? I read this article http://blog.bdoughan.com/2010/10/jaxb-and-shared-references-xmlid-and.html), but changing the #Produces on my JAX-RS to JSON forces an endless loop. Basically i want to reduce an object to it`s id:
public class Foo {
private long id;
private String someText;
private Bar bar;
}
I want this to bind instances of this like so:
{
"id": 1234,
"someText": "lorem",
"bar_id": 9876
}
This is what i want to avoid:
{
"id": 1234,
"someText": "lorem",
"bar": {
"id": 9876,
"anotherText": "ipsum"
}
}

Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
With MOXy as your JSON-binding provider the shared references post you referenced (from my blog) will work for JSON just as it does for XML. Since you are using JAX-RS below is an example of configuring MOXy in that environment:
http://blog.bdoughan.com/2012/05/moxy-as-your-jax-rs-json-provider.html
When using #XmlID/#XmlIDREF it is expected that the object being reference by its ID also exist in the document. Since this isn't your use case you would be better off using an XmlAdapter. The XmlAdapter would have a signature similar to:
public class BarAdapter extends XmlAdapter<Integer, Bar> {
...
}
In the XmlAdapter you would be responsible for returning the id from the instance of Bar during the marshal, and for returning an instance of Bar based on the id during an unmarshal.

Related

JSON to #RelationshipEntity (via Spring Boot)

I'm learning Neo4j and using it through spring-data-neo4j, but I'm struggling to make it work for my needs.
Basically I want to represent this:
A -[{...relationshipKey}]-> B
i.e. A contains a map of Bs, and each key of the map is represented by the property relationshipKey. I do this because AFAIU it's not possible for Neo4J to store a map.
So I'm using #RelationshipEntity like this:
#Data
#NodeEntity
class A {
#Relationship(type = "CONTAINS_B")
Set<ContainsB> containsB;
}
#RelationshipEntity(type = "CONTAINS_B")
#Data
class ContainsB {
#GraphId Long id;
#StartNode A a;
#EndNode B b;
#Property RelationshipKey relationshipKey; // an enum
}
#Data
#NodeEntity
class B {
// Whatever
}
And I'm trying to save a new graph using a spring-boot controller to which I pass a JSON.
Controller:
#PostMapping(value = BASE_PATH + "/create")
A createA(#RequestBody #NonNull A a) {
return ARepository.save(a);
}
JSON:
{
"containsB": [{
"relationshipKey": "key1",
"b": {"someB": "properties"}
},{
"relationshipKey": "key2",
"b": {"someB": "different properties"}
}]
}
Yet when I invoke the controller, I get this exception:
org.neo4j.ogm.exception.MappingException: Relationship entity A(...)
cannot have a missing start or end node
When I debug the controller invocation, a.getContainsB().iterator().next().getA() is null but a.getContainsB().iterator().next().getB() is instantiated and has the correct properties.
If I do this before the repository saving, then it seems to works fine, and A and B are correctly related:
a.getContainsB().iterator().next().setA(new A())
Is there a way to pass a JSON that will be correctly interpreted by Neo4J?
Reason for the error
Your JSON is defining an instance of A with two relationships "ContainsB", which are represented by a #RelationshipEntity in the domain model. However, the definition of "ContainsB" in the JSON does not itself contain a reference to its enclosing A, so when each ContainsB is created it has no reference A.
Solutions
There are a couple of things you could try.
The obvious one is to create instances of "ContainsB" instead:
{
"relationshipKey": "key1",
"a": { ... },
"b": { ... }
}
Another option is to use a JSON generator that allows you to create object references and refer to them internally in your definition. The JSOG format will allow you to do this, and is compatible with Jackson. See https://github.com/jsog/jsog for more details.

How to parse json arrary?

I have come across a problem of parsing json data . I am building project using spring boot based on REST api . When i have to parse data corresponding to domain then it is very easy , i use RequestBody in controller method with domain name but in current scenerio i have a list of domain in json form :
{
"data":[
{
"type":"abc",
"subtypes":[
{
"leftValue":"BEACH",
"rightValue":"MOUNTAIN",
"preferencePoint":60
},
{
"leftValue":"ADVENTURE",
"rightValue":"LEISURE",
"preferencePoint":60
}
]
},
{
"type":"mno",
"subtypes":[
{
"leftValue":"LUXURY",
"rightValue":"FUNCTIONAL",
"preferencePoint":60
},
{
"leftValue":"SENSIBLE",
"rightValue":"AGGRESIVE",
"preferencePoint":0
}
]
}
]
}
I am sending data in list where type is the property of class Type
and class Type has list of Subtypes class and subtype class contains leftValue and rightValue as enums
I am using spring boot which uses jackson liberary by default and i want to parse this data into corresponding Type class using Jackson. Can any one provide me solution.
It wasn't clear to me if you have static or dynamic payload.
Static payload
For static one, I would personally try to simplify your payload structure. But your structure would look like this. (I skipped getters and setters. You can generate them via Lombok library).
public class Subtype{
private String leftValue;
private String rightValue;
private int preferencePoint;
}
public class Type{
private String type;
private List<Subtype> subtypes;
}
public class Data{
private List<Type> data;
}
Then in your controller you inject Data type as #RequestBody.
Dynamic payload
For dynamic payload, there is option to inject LinkedHashMap<String, Object> as #RequestBody. Where value in that map is of type Object, which can be casted into another LinkedHashMap<String, Object> and therefore this approach support also nested objects. This can support infinite nesting this way. The only downside is that you need to cast Objects into correct types based on key from the map.
BTW, with pure Spring or Spring Boot I was always able to avoid explicit call against Jackson API, therefore I don't recommend to go down that path.

Spring Boot REST display id of parent only in a JSON response

Assume I have the following class:
public class ChildEntity {
...
#ManyToOne
private ParentEntity parent;
...
}
Now, I have a REST endpoint that retrieves a child entity object from the database, thus my JSON is the following:
{"id": "123", "name":"someName", "parent": { //parent fields here } ... }
I want to format my JSON responses in another way. I want parent display only the id from the database, instead of the whole object:
{"id": "123", "name":"someName", "parentId": "1" ... }
Basically returning entities directly from endpoints isn't a good idea. You make very tight coupling between DB model and responses. Instead, implement a POJO class that will be equivalent of the HTTP response you sent.
This POJO will have all ChildEntity fields and parentId only and will be constructed in HTTP layer.
Please, see the discussion in comments, basically such an object returned from web layer is not a DTO according to me.
I am annotating #JsonIgnore which ever field I do not want to be part of JSON response. Creating parallel POJO for each entity is costly affair.
#JsonIgnore
#NotNull
#Column(name="DELETED")
private boolean deleted = false;

List becomes String when Marshalling object to json

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!

Jackson JSON to Java mapping for same attrubute with different data type

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).