I have seen in a lot of places that a resource class in a dropwizard project has methods for GET and POST. These methods then access data from the database using the DAO and return back a json
public class DropwizardResource {
private DropwizardDAO ddao;
public DropwizardResource (DropwizardDAO ddao) {
this.ddao = ddao;
}
#GET
#Timed
#UnitOfWork
public List<String> getAllResources() {
return ddao.findAll();
}
}
Is it advisable to have a resource initialized with other clients for some other service and then have the json returned by manual conversion?
public class DropwizardResource {
private NonDbClient client;
public DropwizardResource (NonDbClient client) {
this.client = client;
}
#GET
#Timed
#UnitOfWork
public List<String> getAllResources() {
return toJson(client.findAll());
}
}
First off, let's be clear: you can do whatever you like in a Dropwizard resource - there's nothing inherently special about them.
On your specific question on whether you can use "[a client] for some other service" (e.g. another Dropwizard service, or something completely separate), the answer is yes, that's perfectly fine. Note, however, if you're not using Hibernate to access a database within your resource method, you don't need the #UnitOfWork annotation (which is for declaring that a session & transaction should be managed for you when that method is called).
Finally, you ask whether it's okay to "then have the json returned by manual conversion". It's a little hard to answer that question without knowing what client you're thinking of using, and what it returns when you call its findAll method. I can think of a couple of possible scenarios:
You get deserialised plain old Java objects back from your client (regardless of how they were serialised in transit - JSON, XML, crazy proprietary binary protocol, whatever). In this case, you just need to transform these into whatever object you want to return from your Dropwizard resource method (a List<String> in the case of your example). From there, Jersey and Jackson will deal with serialising this to JSON for you and putting that in the response from your resource.
You get a string containing JSON back from your client. In this case, you'll need to manually deserialise the JSON to Java objects (using a Jackson ObjectMapper - you can grab one from the Dropwizard Environment in your application's run method). At that point you can transform then and return them as in the above case.
In either case, I can't think why you'd want to be serialising to JSON (as in your example). That'd give you a String (not a List<String>). Unless you're doing something pretty quirky, you probably don't want to be returning a JSON string from your Dropwizard resource - that will then serialise it as JSON again, and will then result in a string full of JSON being deserialised again at the other end!
Related
I am writing a REST Client for one of the Vendor REST Service. I use jersey 2.x and JSON-P, below are dependencies I add.
<dependencies>
<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-processing</artifactId>
<version>2.26</version>
</dependency>
<dependency>
<groupId>org.glassfish.jersey.core</groupId>
<artifactId>jersey-client</artifactId>
<version>2.26</version>
</dependency>
</dependencies>
I successfully write code for GET request and received JSON output. I saved it to a file and used JSON-P to interpret and do my own logic without any issues.
But now I need to write a POST request. When I use CURL as below I am able do it. and want to implement the same using Jeresey 2.x and JSON-P.
curl -v -H "Accept:application/json" -H "Content-Type:application/json" -u user:password -X POST --databinary #./InputParameters.json https://<IP>:<PORT>/Configuration/server
InputParameters.json contents
{
"ip": "10.197.70.16",
"partNumber": 202067,
"model": "IBM P7"
}
When I tried to pass response body as String in JSON format ({"ip": "10.197.70.16", "partNumber": 202067, "model": "IBM P7"}), but didn't work. So tried as JsonObject as below still didn't work.
JsonObject jsonObj = Json.createObjectBuilder()
.add("ip", "10.197.70.16")
.add("partNumber", 202067)
.add("model", "IBM P7")
.build();
response = invocationBuilder.post(Entity.json(jsonObj));
I know core java, based on that experience I jumped into writing this program and got success with GET but not POST. I doubt I am doing something fundamentally wrong with POST.
Let's unpack what you're doing for a bit. First there's this part:
JsonObject jsonObj = Json.createObjectBuilder()
.add("ip", "10.197.70.16")
.add("partNumber", 202067)
.add("model", "IBM P7")
.build();
This creates a javax.json.JsonObject instance. JsonObject, which is part of the JSON-P Java API, is pretty much what it says: a class to represent a JSON object. A JsonObject instance contains a hierarchy of javax.json.JsonValue instances, which conform to more specific types like JsonArray, JsonString, other JsonObjects and so on. In this regard it's not unlike the classes of the DOM API for representing XML documents (let's hope Oracle keeps the API docs at that URL for a while). But JSON is fortunately a lot more straightforward than XML and DOM.
Your jsonObj instance would contain a JsonString instance with value "10.197.70.16" mapped to name "ip", a JsonNumber with value 202067 (probably represented as BigDecimal) mapped to name "partNumber" and so on.
Next your code executes this:
Entity.json(jsonObj)
javax.ws.rs.client.Entity.json(something) basically states that you want to create an entity that will provide the payload for a JAX-RS client invocation with as Content-Type application/json. In other words, the something you create it for must be transformed to a JSON representation when it's sent to the API, which should expect a JSON payload and know how to handle it. Note that Entity.json(...) has a generic type parameter. The method signature is static <T> Entity<t> json(T entity). So you're creating an instance of Entity<JsonObject> with the payload entity jsonObj.
When this is handed over to the post method of a javax.ws.rs.client.Invocation.Builder instance (the post method is actually defined in its parent interface SyncInvoker) the client implementation goes to work.
response = invocationBuilder.post(Entity.json(jsonObj));
It takes the provided Entity instance and its content (our jsonObj), checks what the desired output is of the Entity (this is application/json) and seeks a provider that can turn objects of the given type into that output. In other words, some component must be located that can be given a javax.json.JsonObject and write a representation of it as JSON to an OutputStream. The component handling this could be a javax.ws.rs.ext.MessageBodyWriter that claims it can perform this transformation and was registered to the JAX-RS runtime. Various libraries supply such providers and you can also write your own. This makes JAX-RS extensible to deal with various scenarios, handle non-standard input and output or lets you tune its behaviour. When multiple providers are capable of handling the given entity type and producing the desired output, there are rules to determine which one takes on the job. Note that this can depend on what is on your classpath. There are ways of forcing this explicitly.
The client puts together the invocation through its configuration, using the proper URL, query parameters, HTTP method, headers and so on. The payload is created by writing the entity to an OutputStream in the required format. In your example this results in a POST to the server. When the invocation has been completed you receive a javax.ws.rs.core.Response that you can use to determine the HTTP result code and retrieve a response payload, if any. The readEntity(Class<T> entityType) method of Response works like the reverse of turning an Entity into a payload. It searches for a MessageBodyReader that can interpret the response stream according to the value returned from response.getMediaType() and can create an instance of Class entityType from it.
So with all of that explained, what exactly is going wrong in your approach? Well, the issue is that the default implementations available to your JAX-RS runtime probably don't have a writer specifically for an input of type JsonObject and with expected output application/json. It may seem very logical if the server expects JSON, that you should be able to supply a JsonObject as payload. But if the JAX-RS implementation can't find something to handle that class, then at best it can just use some default approach. In that case it may try to interpret the object as a POJO and serialize it to JSON in a default manner, which could lead to weirdness like this:
{
"valueMap": {
"ip": {
"value": "10.197.70.16"
},
"partNumber": {
"num": 202067,
"integral": TRUE
},
...
}
}
That's what a literal interpretation of the JsonObject instance could look like, depending on which implementation it uses and what is used by JAX-RS to turn it into JSON output. Of course it's possible that the object can't be serialized to JSON at all, either because no suitable MessageBodyWriter can be found or it runs into an error when creating the output.
A first solution would be a very simple one. Just turn the JsonObject into a String and simply provide that as the entity:
StringWriter stringWriter = new StringWriter();
try (JsonWriter jsonWriter = Json.createWriter(stringWriter);) {
jsonWriter.writeObject(jsonObject);
} // some error handling would be needed here
String jsonPayload = stringWriter.toString();
response = invocationBuilder.post(Entity.json(jsonPayload));
It seems you had already tried that. A possible problem with this is that the MessageBodyWriter that gets used needs to just output the String's bytes in a suitable encoding (probably UTF-8) when presented with a String as output and application/json as the required content type. Some may not do that. You could try Entity.entity(jsonPayload, MediaType.TEXT_PLAIN_TYPE.withCharset("UTF-8")) but then the server might reject the call.
Other possible solutions are
Writing your own MessageBodyWriter for String objects with an #javax.ws.rs.Produces(MediaType.APPLICATION_JSON) annotation on it.
Better yet, writing such a class that accepts JsonObject instances.
Creating POJO classes for your JSON structure and letting those get used for generating JSON from instances or deserializing JSON responses to instances.
Finding an extension library that contains suitable providers for dealing with javax.json classes.
The addition of the com.owlike:genson dependency to your project is exactly the application of that last suggestion. The Genson library provides conversions between Java objects and JSON in both directions, as well as data binding. Part of its code base is dedicated to JAX-RS providers, among which a class suitable for accepting JsonObject as input.
Issue is resolved after adding below dependency. At this point I am not sure on what does it do.
Thanks to Swamy (TCS) for his support to resolve this.
<dependency>
<groupId>com.owlike</groupId>
<artifactId>genson</artifactId>
<version>1.4</version>
</dependency>
Example using genson
String serialize = new Genson().serialize(
Json.createObjectBuilder()
.add("ip", "10.197.70.16")
.add("partNumber", 202067)
.add("model", "IBM P7")
.build()
);
response = invocationBuilder.post(Entity.json(serialize));
I am trying to develop a microservice using Spring MVC and Spring Boot. In my service I am giving result back as JSON encoded format. Currently I added action like:
#RequestMapping("/checkUsers")
public String checkLogin() throws JsonProcessingException {
ObjectMapper mapper = new ObjectMapper();
List<Users> useObj = (List<Users>) userRepo.findAll();
return(mapper.writeValueAsString(useObj));
}
And now I found the other options through the following method
produces={"application/json; charset=UTF-8"}
Here I am not sure which method is properly using for encoding the data into JSON format in Spring. How can I proceed?
Why don’t you just use
ResponseEntity
And return
new ResponseEntity<String>(“your message”, HttpStatus.OK);
#RequestMapping(method = GET, value = "my/random/uri", produces = "application/json;charset=UTF-8")
Here produces attribute inside my #RequestMapping annotation is the producible media types of the mapped request. The format is a single media type or a sequence of media types, with a request only mapped if mentioned one matches one of these media types. and here, my #RequestMapping annotation is already serving my purpose of encoding.
Now somewhere from Spring Boot documentation:
Spring Boot is a brand new framework designed to simplify the bootstrapping and development of a new Spring
application. The framework takes an opinionated approach to
configuration, freeing developers from the need to define boilerplate
configuration.
Please don't kill the purpose of Spring Boot. :)
Additionally, I would suggest you use org.springframework.http.MediaType class. It has got all encoding types you'll ever require. Happy coding.
Please let me know if you face any difficulty while going with suggested approach.
If you use #RestController on your controller, all request mappings will produce application/json by default.
Also, there is no need to to the object mapping yourself, just return the object without mapping and let Spring/Jackson do its thing.
#RestController
public class UsersController {
// #RequestMapping("/checkUsers")
// There is an even simpler and more concise
#GetMapping("/checkUsers")
public List<User> checkLogin() throws JsonProcessingException {
return userRepo.findAll();
}
}
Given this repository
#RepositoryRestResource( path = "u", itemResourceRel="ui", collectionResourceRel = "us")
public interface IUserRepository extends CrudRepository<Users, Long> {
}
When I go through a controller to call my service method findAllUsers(). I transform the
list of entities result (returned by userRepository.findAll() method provided for free) to a list of domain model objects. This list of domain model objects will get properly deserialize into JSON because I am controlling how to do the deserialization. There is a specific reason why I am doing this, see further below.
Now, if I want to use the userRepository directly, I am running into a loop during the serialization because the object being deserialized are coming from the library com.vividsolutions.jts.geom.Geometry. This class contains a method as described below
Geometry getEnvelope() Returns this Geometrys bounding box.
During the deserialization, jackson runs into a loop, because of it. I am able to correct the deserialization process within my controller. How could I intercept the deserialization from a CrudRepository?
The first idea that came to me was to create an implementation of my interface and override all methods, but it defeats the purpose of doing boiler-plate code.
You show the usage of #RepositoryRestResource I am assuming you're using Spring Data REST to export your repositories. For standard Spring MVC marshaling configuration see the reference docs.
Precisely speaking, you're not intercepting the repositories. Spring Data REST uses Jackson to marshal and unmarshal the responses and requests. Hence you simply customize the Jackson ObjectMapper that SD REST will use. To do so, you extend RepositoryRestMvcConfiguration and override configureJacksonObjectMapper(…):
class MyConfiguration extends RepositoryRestMvcConfiguration {
protected void configureJacksonObjectMapper(ObjectMapper mapper) {
// register custom serialializers, modules etc.
}
}
For customization options in general, have a look at the Jackson reference documentation.
Hi I tried googling around but cannot find solution that I want to achieve.
Example to map json to java object we do
#POST
#Consumes(application/json)
#Produces(application/json)
public Response createUpdateDeleteManualClinicalData(MyJavaPojo definedPojo) {
// this maps any json to a java object, but in my case I am dealing with generic json structure
}
What I want to achieve is Keep it as json object itself
public Response createUpdateDeleteManualClinicalData(JSONObject json)
Work around: I can get data as plain text and convert that to json. But its an overhead from my side which I want to avoid.
Edit: I am open to using any Json library like JsonNode etc... as far as I get Json object Structure directly without the overhead of String to Json from my side. This should be common usage or am I missing some core concept here.
It was a straight solution that I happened to overlooked... my bad.
Jersey is way smarter than I thought... curious to know what magic happens under the layers
#POST
#Consumes(application/json)
#Produces(application/json)
public Response createUpdateDeleteManualClinicalData(JsonNode jsonNode) {
//jsoNode body casted automatically into JsonNode
}
What is the web.xml configuration you are using? Is it something similar to here web.xml setup gists for Jersey1 and Jackson2?
If you are using the same configuration as web.xml setup gists for Jersey1 and Jackson2, then you may do as below. This is a possible alternative than using JSONObject
#POST
#Path("/sub_path2")
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Map<String,Object> saveMethod( Map<String,Object> params ) throws IOException {
// Processing steps
return params;
}
OK, here goes, hopefully this makes sense! I have a small project based off of the appfuse web service only archetype. I have a business facade which has a DAO injected, through this DAO I request some data, simple example:
PersonManager.java
#GET
#Path("{people}")
List<Person> getPeople(#QueryParam("surname") String surname);
PersonManagerImpl.java (implements PersonManager)
public List<Person> getPeople(String surname) {
return personDao.getPeople(String surname);
}
I can make a request to invoke this method through a URL configured to point to "getPeople", however, as the DAO returns the list of people as an array list, I get the following error
Error serializing the response, please check the server logs, response class : ArrayList.
I know I can wrap this method and use Jackson Object Mapper to change the list to a string, but I didn't want another layer in my code, just to marshal JSON requests/responses.
I also don't want to change the interface to return a string, because the interface may be used later to return other data types, thus, I don't want to lock it in to only returning a string representing JSON.
My dilemma is that, I don't quite get how keeping the above interface and implementation, I can have Jackson convert the list of people to a json list of people, with annotations only!
Any help is greatly appreciated.
Please help!
Upgrading Jackson from 1.7.1 to 1.9.5 resolved this issue.