I have a java API (rest) that accepts a JSON as body request.
I need to map the body to a java class, but one of the JSON attributes is a JSON itself, and I cannot predict its structure.
For example, this is the resource:
#POST
public void paymentInfo(PaymentInfoEntity paymentInfoEntity)
throws JsonGenerationException, JsonMappingException, IOException {
...
}
This is a JSON example:
{
progressive: 123,
params: { [another valid JSON node] }
}
This is how I'd like the entity:
public class PaymentInfoEntity {
public Integer progressive;
public JsonNode params;
}
With this configuration, I have this error:
org.codehaus.jackson.map.JsonMappingException: Can not construct
instance of com.fasterxml.jackson.databind.JsonNode, problem: abstract
types can only be instantiated with additional type information
The same error occour if I declare BaseJsonNode params instead of JsonNode params.
If I declare, instead, a Object params, it works.
How can I then parse a JSON from this? In this case params.toString() is the form {key1=stringvalue1, key2=stringvalue2} instead of {key1: "stringvalue1", key2: "stringvalue2"}.
Which is the best option to achieve my goal?
Thank you!
JsonNode is an abstract type. Try to use BaseJsonNode
or java.util.Map
Related
I would like to deserialize a json string to a java object. I wanted to write a generic method.
public class ObjectSerializer<T> {
T t;
private ObjectMapper mapper = new ObjectMapper();
/* public Person deSerial(String json) throws Exception {
TypeReference<Person> typeRef = new TypeReference<Person>() {};
return mapper.readValue(json, typeRef);
} */
public T deSerialize(String jsonInput) throws Exception {
TypeReference<T> typeRef
= new TypeReference<T>() {};
return mapper.readValue(jsonInput, typeRef);
}
}
When I call deSerialize(validPersonJsonString) [validPersonJsonString : valid person JSON String], it is not working, it it throwing me the error:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.example.Person.
Whereas, when in call the commented deSerial method, it works fine. Please explain the issue.
Thanks.
Jackson doesn't support TypeReference with generic type parameters because of type erasure. Here's the bug about it.
As far as your use case is concerned, you don't need to use ObjectSerializer class at all. You can directly expose ObjectMapper object to your service layer and perform the deserialization.
If you want to shield the json serializing mechanism from your service layer then you can wrap ObjectMapper implementation into another class (like you have done in your code) but then, accept the class type as a method argument rather than a generic type.
I've a filter through which POST REST api goes with and i want to extract the below part of my payload in the filter.
{
"foo": "bar",
"hello": "world"
}
Filter code :-
public class PostContextFilter implements ContainerRequestFilter {
#Override
public void filter(ContainerRequestContext requestContext)
throws IOException {
String transactionId = requestContext.getHeaderString("id");
// Here how to get the key value corresponding to the foo.
String fooKeyVal = requestContext. ??
}
}
I don't see any easy method to get the payload to the api using the ContainerRequestContext object.
So my question is how do i get the key value corresponding to the foo key in my payload.
Whereas filters are primarily intended to manipulate request and response parameters like HTTP headers, URIs and/or HTTP methods, interceptors are intended to manipulate entities, via manipulating entity input/output streams.
A ReaderInterceptor allows you to manipulate inbound entity streams, that is, the streams coming from the "wire". Using Jackson to parse the inbound entity stream, your interceptor could be like:
#Provider
public class CustomReaderInterceptor implements ReaderInterceptor {
// Create a Jackson ObjectMapper instance (it can be injected instead)
private ObjectMapper mapper = new ObjectMapper();
#Override
public Object aroundReadFrom(ReaderInterceptorContext context)
throws IOException, WebApplicationException {
// Parse the request entity into the Jackson tree model
JsonNode tree = mapper.readTree(context.getInputStream());
// Extract the values you need from the tree
// Proceed to the next interceptor in the chain
return context.proceed();
}
}
This answer and this answer may also be related to your question.
I am trying to deserialize a json object into a java bean.
The main issue I am facing is that I'd like to treat the field object of the json string as a plain string, even if it contains a potentially correct json object.
The json structure is like this:
{
"type":"user",
"object":{
"id":"1",
...}
}
How can i tell gson to ignore the object value so that it doesn't get deserialized into an object? I'd like it only to be mapped to a plain String field in my bean so that I can dispose a proper deserialization for it, once I got the type from the type field.
Just declare it as of type JsonObject
class ExampleJsonModel {
#SerializedName("type")
public String type;
#SerializedName("object")
public JsonObject object;
}
I don't know if your problem is solved. I ran into a similar question and here it is how I worked it out:
JsonDeserializer allows you to make you own adapter to deserialize that **:
class JavaBeanDeserializer implements JsonDeserializer<JavaBeanObject>() {
public JavaBeanObject fromJson(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// return JavaBeanObject built using your logic.
}
You've to register JavaBeanDeserializer to Gson object when building it:
Gson gson = new GsonBuilder().registerTypeAdapter(JavaBeanObject.class, new JavaBeanDeserializer()).create();
I am building an REST API with JAX-RS. I have POST that consumes an JSON element:
The element is a class:
#XmlRootElement
public class EventData{
public long start;
public long end;
public Collection<Person> persons;
}
I have an method like this:
#POST
#Consumes({MediaType.APPLICATION_JSON})
public Response transactionRequest(EventData insert){
....}
if I post a JSON String of an EventData it works fine, but if I switch to:
#POST
#Consumes({MediaType.APPLICATION_JSON})
public Response transactionRequest(ArrayList<EventData> insert){
....}
and send an JSON String like this "{eventData:[{start:x,end:y,persons:[....]}]" it will build the ArrayList and its EventData objects, but the EventData object variables are null.
Can anybody help?
You need to send a JSON array consisting of JSON objects representing your EventData class.
The sample you've given isn't such a JSON array, but a JSON object with a single property named 'eventData' containing an JSON array.
Try something like this (based on your EventData class):
[
{ "start":1, "end":2, "persons":[] },
{ "start":3, "end":4, "persons":[] }
]
Notice that there is no mention of your EventData class, because JSON has no concept of named types -- it's just objects and arrays of objects; only the properties of objects have names.
I am trying to deserialize a json object into a java bean.
The main issue I am facing is that I'd like to treat the field object of the json string as a plain string, even if it contains a potentially correct json object.
The json structure is like this:
{
"type":"user",
"object":{
"id":"1",
...}
}
How can i tell gson to ignore the object value so that it doesn't get deserialized into an object? I'd like it only to be mapped to a plain String field in my bean so that I can dispose a proper deserialization for it, once I got the type from the type field.
Just declare it as of type JsonObject
class ExampleJsonModel {
#SerializedName("type")
public String type;
#SerializedName("object")
public JsonObject object;
}
I don't know if your problem is solved. I ran into a similar question and here it is how I worked it out:
JsonDeserializer allows you to make you own adapter to deserialize that **:
class JavaBeanDeserializer implements JsonDeserializer<JavaBeanObject>() {
public JavaBeanObject fromJson(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
// return JavaBeanObject built using your logic.
}
You've to register JavaBeanDeserializer to Gson object when building it:
Gson gson = new GsonBuilder().registerTypeAdapter(JavaBeanObject.class, new JavaBeanDeserializer()).create();