JSON, JAXB,JSON Rest - json

I created a Rest Service which has is working fine in XML request ( Rest Service input JAXB generated class ). When I am trying to send a Json Request, It's throwing an exception.
SEVERE: The exception contained within MappableContainerException could not be mapped to a response, re-throwing to the HTTP container
org.codehaus.jackson.map.JsonMappingException: Can not instantiate value of type [simple type, class Transaction] from JSON String; no single-String constructor/factory method (through reference chain:
class Transaction which is inner class .
My Request class is generated from schema using JAXB, My getter method is like below but no setter method.
public List<Transaction> getORIG() {
if (origtrans == null) {
origtrans = new ArrayList<Transaction>();
}
return this.origtrans;
}
My Json Request below
{
"LOB_CD": "42424"
"ORIGINALTRANSACTION" : [
"LOGON_ID" : "TEST"
]
}
When I am addiong original Transaction it's throwing an error otherwise it's working fine.
Can you please help me out with this.
Thanks in advance.

First of all make sure you are using a valid JSON, like:
{
"LOB_CD": "42424",
"ORIGINALTRANSACTION": {
"LOGON_ID": "TEST"
}
}
Also, it would be nice if you could show us the Transaction class.

It works.
I did following steps
1) Added an empty constructor
2) Added this annotation for the list
#JsonDeserialize(as=ArrayList.class, contentAs=Transaction.class)
3) change a Json Object to
{ "LOB_CD": "42424" "ORIGINALTRANSACTION" : [ { "LOGON_ID" : "TEST" } ] }
Thanks a lot,
Patel

Related

Understanding Spring HATEOAS error: Embedded wrapper returned null for both the static rel and the rel target type

As mentioned, I would like to get help understanding this error which is quite cryptic to me:
WARN 6436 --- [nio-8080-exec-4] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: Embedded wrapper org.springframework.hateoas.server.core.EmbeddedWrappers$EmbeddedCollection#7538c537 returned null for both the static rel and the rel target type! Make sure one of the two returns a non-null value!; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Embedded wrapper org.springframework.hateoas.server.core.EmbeddedWrappers$EmbeddedCollection#7538c537 returned null for both the static rel and the rel target type! Make sure one of the two returns a non-null value! (through reference chain: org.springframework.hateoas.CollectionModel["_embedded"])]
This error came about after I tried accessing a collection model through the following method within my Spring Controller. What I'm trying to do is to return all the share transactions associated with a particular stock code.
#Autowired
private ShareTransactionAssembler shareTransactionAssembler;
#GetMapping("/{stockCode}/transactions")
public CollectionModel<ShareTransactionModel> getShareTransactions (#PathVariable("stockCode") String stockCodeString) {
StockCode stockCode = new StockCode(stockCodeString);
List<ShareTransaction> shareTransactionList = stockQueryService.getShareTransactions(stockCode);
return shareTransactionAssembler.toCollectionModel(shareTransactionList, stockCode);
}
The following is my shareTransactionAssembler code:
#Component
public class ShareTransactionAssembler extends RepresentationModelAssemblerSupport<ShareTransaction, ShareTransactionModel> {
public ShareTransactionAssembler() {
super(StockController.class, ShareTransactionModel.class);
}
#Override
public ShareTransactionModel toModel(ShareTransaction shareTransaction) {
String stockCodeString = shareTransaction.getStock().getStockCode().getStockCodeAsString();
Link selfLink = linkTo(
methodOn(StockController.class)
.findShareTransaction(stockCodeString, shareTransactionModel.getId())
)
.withSelfRel();
shareTransactionModel.add(selfLink);
Link stockLink = linkTo(
methodOn(StockController.class)
.findStock(stockCodeString)
)
.withRel("Stock");
shareTransactionModel.add(stockLink);
return shareTransactionModel;
}
public CollectionModel<ShareTransactionModel> toCollectionModel (List<ShareTransaction> shareTransactionList, StockCode stockCode) {
CollectionModel<ShareTransactionModel> shareTransactionModels = super.toCollectionModel(shareTransactionList);
Link selfLink = linkTo(
methodOn(StockController.class)
.getShareTransactions(stockCode.getStockCodeAsString())
)
.withSelfRel();
shareTransactionModels.add(selfLink);
return shareTransactionModels;
}
}
In case you need to know, accessing the individual share transactions seem to work fine. An example JSON response is as follows:
{
"id": 1,
"transactPrice": "13.00",
"commissionPaid": "1.05",
"transactTimeDate": "2020-03-07T13:05",
"transactUnits": 30,
"_links": {
"self": {
"href": "http://localhost:8080/stock/NVDA/transactions/1"
},
"Stock": {
"href": "http://localhost:8080/stock/NVDA"
}
}
}
I would really appreciate if you can shed some light on this! Thanks!
I stumbled onto this error as well. I got it fixed by extending my model class with RepresentationModel instead of EntityModel.
Still searching why this makes a difference..
I had this problem too and this is my understanding based on reading the documentation here (see section 2.4):
https://docs.spring.io/spring-hateoas/docs/current/reference/html/#reference
You are not supposed to directly inherit from EntityModel. EntityModel is a generic RepresentationModel implementation that can be used for representing singular objects or concepts. You can use it when you don't want to write your own RepresentationModel. It should just serialize all fields in the object you pass it.
RepresentationModel is the root class for defining your own representation models.

Handel JSON of different type in Spring POST request

I keep getting Bad request 400 when trying to POST this array of JSON objects "sorry bad format":
{
"type":"input","uniqueId":434,"label":"name","viewToCall":"input-configuration-menu"},{"type":"button","uniqueId":930,"label":"name","viewToCall":"button-configuration-menu"}]
Im not sure how to handel different type of json object in my #Requestbody:
#RequestMapping(value="/saveForm", method = RequestMethod.POST)
public #ResponseBody void saveForm( #RequestBody ArrayList<Components> text ){
do somthing...
}
I found this resourcer but I dont have the experience to get it to work i n web environment:
Spring #RequestBody containing a list of different types (but same interface)
http://programmerbruce.blogspot.com.es/2011/05/deserialize-json-with-jackson-into.html
http://aredko.blogspot.se/2012/04/json-for-polymorhic-java-object.html
There is a missing [ at the beginning of the JSON, otherwise it's valid JSON. If the problem is not the missing angle bracket, put the logs in DEBUG or TRACE, and post the stacktrace.
Also the components need to be annotated with something like this, in order for Jackson to know which object need to be instantiated (see also Jackson polymorphism without annotations):
#JsonTypeInfo(use=JsonTypeInfo.Id.NAME, include=As.WRAPPER_OBJECT)
#JsonSubTypes({
#Type(value=Input.class, value="input"),
#Type(value=Button.class, value="button")})
public interface Component {
...
}
#JsonTypeName("type")
public Sub1 implements Component {
}
#JsonTypeName("button")
public Button implements Component {
}

Jackson JSON parsing, how to map 2 possible objects into one master object

I'm using Jboss Resteasy and Jackson to marshall a response into an object. The problem is that the API I'm connecting to either returns a single object of type A if it's an error or a list of objects of type B if it is successful. My goal would be to have an object C like the following:
class C {
A a;
List<B> bList;
}
However, when I try this I get (in the case where it returns success)
Caused by: org.codehaus.jackson.map.JsonMappingException: Failed to narrow content type [collection type; class java.util.List, contains [simple type, class com.B]] with content-type annotation (com.C): Class com.C is not assignable to com.B
at org.codehaus.jackson.map.deser.BasicDeserializerFactory.modifyTypeByAnnotation(BasicDeserializerFactory.java:797)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.constructSettableProperty(BeanDeserializerFactory.java:1375)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.addBeanProps(BeanDeserializerFactory.java:1182)
at org.codehaus.jackson.map.deser.BeanDeserializerFactory.buildBeanDeserializer(BeanDeserializerFactory.java:707)
I'm just not sure what kind of #Json annotations I would need (or even if this possible)
You won't be able to sort it out like that. RestEasy will look at your class C and it won't be able to figure out if your response object contains a class A or a List<B>.
You can solve this sort of deal like this:
public <T> T returnEntityIfValid(ClientResponse response, Class clazz) {
try {
return (T) response.getEntity(clazz);
} catch (RuntimeException ex) {
final A node = (A) response.getEntity(A.class);
throw new RuntimeException("ERROR: " + node.toString());
}
}
The idea is we'll be expecting a specified type, but since the Response object obscures it from us we have to just try and grab the entity. If the response object contains your entity class A it will return it with no problem. Otherwise, it will try and extract it, but throw a JsonMappingException (which isn't throwable from Response.getEntity() hence the RuntimeException) at which point the error will be extracted from your class B
This has been generified to support class extraction of any entity type.

JAX-RS / Jersey ".get(Integer.class)" and single JSON primitive (Integer) values?

I have a JAX-RS WebService with the following method:
#Path("/myrest")
public class MyRestResource {
...
#GET
#Path("/getInteger")
#Produces(APPLICATION_JSON)
public Integer getInteger() {
return 42;
}
When accessed using this snipped:
#Test
public void testGetPrimitiveWrapers() throws IOException {
// this works:
assertEquals(new Integer(42), new ObjectMapper().readValue("42", Integer.class));
// that fails:
assertEquals(new Integer(42), resource().path("/myrest/getInteger").get(Integer.class));
}
I get the following exception:
com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: A message body reader for Java class java.lang.Integer, and Java type class java.lang.Integer, and MIME media type application/json was not found
com.sun.jersey.api.client.ClientResponse getEntity
SEVERE: The registered message body readers compatible with the MIME media type are: application/json
...
The problem is just with returning single primitive values (int/boolean) or their wrapper classes. Returning other POJO classes is not the problemen so I guess all the answers regarding JSONConfiguration.FEATURE_POJO_MAPPING and JAXB annotations do not apply here.
Or which annotation should I use to describe the return type if I don't have access to its
class source?
Using ngrep I can verify that just the String "42" is returned by the webservice. Thats a valid JSON "value" but not a valid JSON "text" according to the spec. So is my problem on the client or the server side?
I tried activating JSONConfiguration natural/badgerfish according to http://tugdualgrall.blogspot.de/2011/09/jax-rs-jersey-and-single-element-arrays.html but with no success (ngrep still shows just "42"). Would that be the right path?
Any ideas are appreciated!
This is a recognized bug in Jackson, which has been touted (incorrectly in my opinion) as a feature. Why do I consider it a bug? Because while serialization works, deserialization definitely does not.
In any case, valid JSON cannot be generated from your current return type, so I would recommend creating a wrapper class:
class Result<T> {
private T data;
// constructors, getters, setters
}
#GET
#Path("/getInteger")
#Produces(APPLICATION_JSON)
public Result<Integer> getInteger() {
return new Result<Integer)(42);
}
Alternatively, you can elect to wrap root values, which will automatically encapsulate your data in a top level JSON object, keyed by the objects simple type name - but note that if this option is used that all generated JSON will be wrapped (not just for primitives):
final ObjectMapper mapper = new ObjectMapper()
.configure(SerializationFeature.WRAP_ROOT_VALUE, true)
.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, true);
final String serializedJson = mapper.writeValueAsString(42);
final Integer deserializedVal = mapper.readValue(serializedJson,
Integer.class);
System.out.println(serializedJson);
System.out.println("Deserialized Value: " + deserializedVal);
Output:
{"Integer":42}
Deserialized Value: 42
See this answer for details on how to retrieve and configure your ObjectMapper instance in a JAX-RS environment.

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!