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.
Related
I have what I believe should be a simple use case.
I would like to serialize a POJO with type metadata (preferably a simple name I come up with, not the fully qualified class/package name), and later have Jackson deserialize the JSON back into the concrete class it came from by using this metadata. There is no inheritance hierarchy among classes being serialized and deserialized.
My scenario is I have a service which accepts multiple file types. For each file uploaded, the client can retrieve JSON data whose structure and type depends on the file it came from. Thus when I retrieve JSON from the service, it's not known what the concrete class is to deserialize to. I would like Jackson to figure this out based on metadata which it supplies.
For example, I'd like to be able to do this:
String json = ... // get JSON from the service
Object obj = mapper.readValue(json, Object.class) // concrete class is not known
System.out.println(obj.getClass()) // I want this to be MyConcreteClass.class
There is no inheritance hierarchy among JSON types returned.
I don't want to reveal package names or other internal service
details/structure.
I have control over Jackson's serialization process
Relevant question: Can jackson determine root object type to deserialize to when json includes type property?
Thank you so much for your help!
This can be achieved using Jackson's JavaType:
String className = "class.name.from.json.service";
JavaType dtoType = TypeFactory.defaultInstance().constructFromCanonical(className);
Object dto = new ObjectMapper().readValue(InputStream, dtoType);
assert dto.getClass().equals(dtoType.getRawClass());
I am looking to get the key and value to each Json formatted call and use them as java objects such as String or Integer ,in a rest client i would enter
{
"Name":"HelloWorld"
}
And i would get back the HelloWorld mapped to its Key so far ive seen examples but im just having trouble finding out what each tag does and how to parse the body to give the above results
#POST
#Path("/SetFeeds")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
#JsonCreator
public String setFeed(String jsonBody,#Context UriInfo uriInfo){
// Code to manipulate the body of the request
return response;
}
First thing you need to understand is how request body parsing is done. In JAX-RS parsing (or unmarshalling/deserializing/whatever) is done with MessageBodyReaders. There are different readers that can handle different Content-Type. For instance if you have Content-Type application/octet-stream, there is a reader that will unmarshal to byte[] or File or InputStream. So the following would work out the box
#Consumes("application/octet-stream")
public Response post(File file) {} // or `byte[]` or `InputStream`
That being said, JAX-RS implementations come with very basic readers for "easily convertible" format. For example, most requests can be converted to String, so you get that free for most Content-Types, as you are with your current code.
If we want some more complex data types, like your HelloWorld for Content-Type application/json, there is no standard reader for this. For this to work, we either need to create our own reader or use a library that comes with a reader. Luckily, the most popular JSON library in Java, Jackson, has implemented a JAX-RS provider that has a reader and a writer (for serialization).
Now depending on what server/JAX-RS implementation you are using, different implementations create light wrappers around the core Jackson JAX-RS module. If I knew the JAX-RS implementation you were using, I could recommend which wrapper to use, or you can forget the wrapper and just go with the basic Jackson module, which is
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
<version>2.2.3</version>
</dependency>
The above is a Maven dependency. If you are not using Maven, then basically you need to download all these jars.
You can find all of them here. Just search for them individually.
Then you need to register the provider. Again it depends on your JAX-RS implementation and how you are handling the configuration of your resource classes. I would need to see your application configuration (either web.xml or Java code) and maybe the server you are using to help with that. For the most part, the JacksonJsonProvider (which is the reader and writer) needs to be registered.
Once you have it registered then you need to understand the basics of how Jackson handles the serialization. At most basic level, Jackson looks for JavaBean properties (basic getter/setter) to match with JSON properties. For instance, if you have this bean property
public class HelloWorld {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
The JSON should look like {"name": "whatever"}. The "name" key is the same as the bean property. In Bean property terms, the name of the property is all letters after the get/set with the first letter lowercased.
That's pretty much all there is to it. Now you can do
#Consumes("application/json")
public Response post(HelloWorld helloWorld) {
String name = helloWorld.getName(); // should == "whatever"
return Response.ok(helloWorld).build(); // we can also return objects
}
For more complex JSON formats, you should refer to the Jackson documentation or ask a question here on SO.
As far as the registering of the JacksonJsonProvider, if you are having trouble, please provide the information I requested, i.e. application configuration (web.xml or Java config) and the server you are using.
See Also:
JAX-RS Entity Provider to learn more about readers and writers
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));
I am trying to serialize an instance of Campaign in Adwords API with gson at first with the code below:
Campaign c = new Campaign();
c.setName("beijing");
c.setId(23423L);
Gson gson = new Gson();
String json = gson.toJson(c);
and I get the exception that class Money declares multiple JSON fields named __equalsCalc. When I try to serialize the instance with json plugin of struts2 with the code below
String str = org.apache.struts2.json.JSONUtil.serialize(c);
System.out.println(str);
It works and output the correct result
{"adServingOptimizationStatus":null,"biddingStrategy":null,"budget":null,"campaignStats":null,"conversionOptimizerEligibility":null,"endDate":null,"frequencyCap":null,"id":23423,"name":"beijing","networkSetting":null,"servingStatus":null,"settings":null,"startDate":null,"status":null}
Then my question is that why can the json plugin of struts2 can serialize the instance correctly while gson cannot? Can I use the json plugin of struts2 to serialize objects to json since it is design to produce json result in struts2 not for this situation.
You can use the json plugin in struts2 to serialize your object manually to json string. You can do that by calling the serialize static method.
String jsonString = JSONUtil.serialize(your_object);
Don't forget to include xwork-core jar in your classpath because it depends on it.
Sounds like either a bug in Gson or it is more particular/less robust. Without looking at the code for either it would be hard to know more.
Personally I use Jackson for JSON to POJO transformations.
Ultimately as long as the Structs2 plugin is available on your classpath I don't see why you couldn't leverage it's classes to handle JSON transformations. Ultimately JSON is a format therefore all JSON libraries need to produce commonly understandable data.
I had a similar problem and solved it by moving my use of SimpleDateFormat from the class level to inside a method. GSON doesn't have to serialize SimpleDateFormat this way.
Hope this helps someone - 45 minutes of head banging for me! :-)
Does anyone know if there is the ability to generate objects for JSON data? I know there are generic JSON object libraries, but I am looking for more specific - similar to how jaxb can convert SOAP definitions or XSDs into an object model. I know there would need to be some sort of JSON definition file (which I do not know if that concept even exists within JSON), but I feel like that would be a lot more beneficial. Think:
Generic case:
genericJsonObect.get("name");
Specific case:
specificJsonObject.getName();
Jackson and XStream have the ability to map json to POJOs.
Do you want the .java source file to be generated for you? Or to map exiting java beans to JSON objects?
If the former, there is no such a library ( that I'm aware of ) if the later, Google GSON is exactly what you need.
From the samples:
class BagOfPrimitives {
public int value1 = 1;
private String value2 = "abc";
private transient int value3 = 3;
BagOfPrimitives() {
// no-args constructor
}
}
(Serialization)
BagOfPrimitives obj = new BagOfPrimitives();
Gson gson = new Gson();
String json = gson.toJson(obj);
System.out.println( json );
Prints
{"value1":1,"value2":"abc"}
( Deserialization )
BagOfPrimitives obj2 = gson.fromJson(json, BagOfPrimitives.class);
System.out.println( obj2.value1 ) ; // value1 is 1
I think the Jackson data mapper can do what you need. It can serialize/deserialize a real Java object into a Json tree.
But others API should also work :
Sojo
FlexJSON
Gson
I am not familiar of such code generation project, although I am sure many Java JSON library projects would be interested in having such thing. Main issue is that there is good Schema language for JSON that would allow code generation; JSON Schema only works for validation.
However: one possibility you could consider is to just use JAXB to generate beans, and then use Jackson to use those beans. It has support for JAXB annotations so you would be able to work with JSON and beans generated.
I have found this site very useful.
http://jsongen.byingtondesign.com/ and have used it in our projects.