jackson jsonnode property error - java

I want something like this
#Property
public JsonNode node
To be able to pass in directly from the rest api client.
This works in Jackson 1.9 (with no special serialization), but not in 2.1 for some reason. I get an error that says JsonNode can't be deserialized.
I created a class that implements the MessageBodyReader interface, but I'm not sure how to actually use it. How do I make this work?
Are there other workarounds?

Found the problem.
Turns out I was using the wrong JsonNode from org.codehaus.jackson.annotate.JsonProperty when I should be using com.fasterxml.jackson.annotate.JsonProperty

Related

using JsonObject as entity for Jersey 2 response

I have this simple code:
package com.example
import javax.json.Json;
import javax.json.JsonObject;
...
#Path("/")
public class Resource {
#GET
#Produces(MediaType.APPLICATION_JSON)
public Response defaultEntry() {
JsonObject result = (Json.createObjectBuilder()
.add("hello", "world")
.build());
return Response.status(200).entity(result.toString()).build();
}
}
I am new to Java, could someone please explain why, if I omit the call to result.toString() and simply pass result to .entity (like so: return Response.status(200).entity(result).build()), I get JSON on the client that includes type information etc, but not what I expected:
{"hello":{"chars":"world","string":"world","valueType":"STRING"}}
what is the intention of this? How is passing JsonObject to it different from passing a string?
Also, I did not find Response.entity method in the documentation (https://jersey.java.net/apidocs/2.11/jersey/javax/ws/rs/core/Response.html). I copied this code from a tutorial, that did not explain properly what is going on...
I wish I had a better answer for you, this more of a hint until a better answer arrives. There are a few moving parts here. JsonObject is an interface. Its implementation is not described. Furthermore there is a Json serializer that is turning your returned objects into Json text. It is both these things together that is leading to this Json schema output. When you did the .toString() variation, the serializer just returned the String as is. But when you return the JsonObject now you have these two dynamics at play, the implementation of the JsonObject and the implementation of the serializer. Since you are using Jersey 2.0 you could be using Jackson, Moxy, or Jettison serializers. These all might have different output when serializing the JsonObject, but we would have to test to be sure. Furthermore, the JsonObject implementation might be configured in a way that when serialized by your chosen serializer leads to its output being a Json schema, versus just regular Json. This can be done using annotations that are specific to the chosen Json serializer.
In my career I have used multiple Json serializers. Jackson is probably the most popular one out there. But I have also used Gson extensively. In one project we configured Gson in some way where its serialized Json output came out as a Json schema when serializing POJO's. So its not far fetched to have a Json serializer output Json schema under certain conditions.
When serializing POJO's (aka Java Beans), you expect a regular Json output when using default settings of your serializer on a Java Bean. But when sending back objects that could have complex interworkings with specific Json serializers you may get varying Json output.
In this situation you would have to run tests to dive deeper into what is going on. For example, I would first test out the serializer against a POJO that matches the JsonObject you created. Then I would also test out other Json serializers on the same JsonObject. See if you can pick up on a pattern.
The datatype module jackson-datatype-jsr353 provides support for javax.json types. The page includes instructions how to add the dependency and register the module with Jackson's ObjectMapper.
Starting with Jackson 2.11.0, the module moved under the umbrella of jackson-datatypes-misc.

UnrecognizedPropertyException in JSON with JERSEY

We get a org.codehaus.jackson.map.exc.UnrecognizedPropertyException with using Jerseys and Jackson as JSON-Mapper. We have an object with not native type as property (for example: not a String or int). When i use the annotation #JsonIgnore it's ok. But I must have the property.
Does anybody, which annotation should I use? In JAXB it's #XMLType?
We use Jersey 1.9.1 and Jackson 1.9.13.
I solved this. See my comment on the question.

How to use Couchbase Java Client in a Dropwizard Project?

I've been looking at the couchbase-java-client project and wondering whether it's possible to use it inside of a dropwizard project.
It seems like it'd be a natural fit, because couchbase is basically a JSON database, but the java client doesn't seem to be compatible with Jackson. As far as I can tell, the couchbase client library includes its own internal implementation of a JSON library that's incompatible with all the other java JSON libs out there, which is really weird.
I found a JacksonTransformers class that looked promising at first. But upon closer inspection, the library is using a shaded version of Jackson (with a rewritten package of com.couchbase.client.deps.com.fasterxml.jackson.core).
Anyhow, since dropwizard uses Jackson and Jersey for marshalling JSON documents through the REST API, what's the least-friction way of using the couchbase-java-client library? Is it even possible in this case?
It is definitely possible to use Couchbase with Dropwizard. The client SDK provides JSON manipulation objects for the developer's convenience but it also allows for delegating JSON processing to a library like Jackson or GSON.
Take a look at the RawJsonDocument class here.
Basically, you can use a Stringified JSON (coming out of any framework) to create one of those objects and the client SDK will understand it as a JSON document for any operation i.e.:
String content = "{\"hello\": \"couchbase\", \"active\": true}";
bucket.upsert(RawJsonDocument.create("rawJsonDoc", content));
It should be possible to make this work.
Client requests to dw server for Resource Person.
DW server requests to couchebase, gets a Pojo back representing Person or JSON representing person.
If it's JSON, create a POJO with Jackson annotations in DW and return that to client
If it's a special couchebase pojo, map that to a Jackson pojo and return to to client
A solution based on #CamiloCrespo answer:
public static Document<String> toDocument(String id, Object value,
ObjectMapper mapper) throws JsonProcessingException {
return RawJsonDocument.create(id, mapper.writeValueAsString(value));
}
Keep in mind, that you can't use a simply maper, like ObjectMapper mapper = new ObjectMapper(), with Dropwizard.
You can get it from Environment#getObjectMapper() in the Application#run() method, or use Jackson.newObjectMapper() for tests.
An example of using:
ObjectMapper mapper = Jackson.newObjectMapper();
User user = User.createByLoginAndName("login", "name");
bucket.insert(toDocument("123", user, mapper));

How to serialize POJO fields differently based on Accepts header

We have a POJO that contains a collection and have it annotated thus:
#XmlElement(name = "<MyId")
#XmlElementWrapper(name = "MyIds")
private final Set<Long> myIds;
We are using JacksonJaxbJsonProvider in CXF to do the marshalling in our REST service.
The problem we are seeing is that if someone requests application/xml the response is correct, in that the user gets:
<MyIds>
<MyId>123</MyId>
<MyId>456</MyId>
...
</MyIds>
But when application/json is requested, the user gets (note the singular field name):
{
"MyId" : [123, 456, ...]
}
What I want to know is if there's a way to make that plural in the JSON response, and if so, how.
This feels like it may be bug in Jackson but there may be a perfectly good reason this is happening. Also, I realize that if everyone used the same POJO, we wouldn't have to care about what the marshalled text looked like, but in this case, one of the consumers cannot use our POJO.
If you're using version 2.1 or above of Jackson there's a feature which can be enabled to get the behaviour you want
ObjectMapper m = new ObjectMapper()
m.configure(MapperFeature.USE_WRAPPER_NAME_AS_PROPERTY_NAME, true);

How can I send the Object class to server with Jackson?

I have a Message class like this:
class Message {
#JsonProperty("content")
Object content;
}
where the content attribute can be a User, a Post, or a String
and I have to send this object to the server and cast the content to the right class.
I'm using Jackson annotations to serialize the JSON, but when I try to cast the content, an error appears, because the attribute content arrives in the server like a LinkedHashMap object.
The error is:
ERROR [org.apache.catalina.core.ContainerBase.[jboss.web].[default-host].[/MegaRadarSocial].[Resteasy]] (http-localhost-127.0.0.1-8080-1) Servlet.service() for servlet Resteasy threw exception: org.jboss.resteasy.spi.UnhandledException: java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to br.com.megaradar.megaradarsocial.model.User
I would like a help to casting...
Thanks
As you control both ends (server and client), you could try Genson library http://code.google.com/p/genson/. One of its features allows you to serialize to json and type information, this enables you to deserialize back to the right type.
Genson genson = new Genson.Builder().setWithClassMetadata(true).create();
json = genson.serialize(yourMessage);
// then deserialize it back
Message message = genson.deserialize(json, Message .class);
The serialized json will look like : {"content": {"#class":"package.path.Message", ...the object values...}}
You can even define aliases for the serialized classes
new Genson.Builder().addAlias("message", Message.class)
Important: Note that you need to use the same configuration of genson on both sides. So enable type information with setWithClassMetadata and if you use aliases, you must define the same on the client side.
What you need is #JsonTypeInfo annotation, like so:
class Message {
#JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY property="type")
#JsonProperty("content")
Object content;
}
(you can see http://programmerbruce.blogspot.com/2011/05/deserialize-json-with-jackson-into.html for examples)
which would add property "type" with class name as value (there are many alternative ways as well) when serializing, and using that when deserializing.
Thank you for all the answers. But I found another way to convert my Object to any type I want.
I'm using the method convertValue from the ObjectMapper object. Then, I can simulate the casting.
Thanks again

Categories