I'm currently writing a Jersey REST interface. I'm have this code which I'm trying to create the following JSON response and a list of long is been generated a array of string (Using Jaxb and Jackson)
The code looks like :
#XmlElement(name = "visitorProfiles", required = false)
private List<Long> visitorProfiles;
The JSON reponse looks like
{
"visitorProfiles":["45"]
}
And I correct JSON response should be
{
"visitorProfiles":[45]
}
This is what I'm using for the JSON configuration
context = new JSONJAXBContext(JSONConfiguration.natural().rootUnwrapping(true).build(), JerseyResources.getJaxbClasses());
Tried to reproduce the case with no success, I can't see any reason for this to happen unless the natural context wasn't apply correctly for that class
Related
I'm declaring FeignClient with Spring Cloud OpenFeign version 4.0.1. The API I'm calling expects in request body primitive JSON string value (e.g. "something") as a string in quotes. But I'm struggling with implementing it using Feign.
Code sample:
#FeignClient(value = "client", url = "https://${example.host}:${example.port}/api/2/", dismiss404 = true)
public interface ExampleClient {
#GetMapping(value = "/path/to/resource", produces = MediaType.APPLICATION_JSON_VALUE)
String getResourceValue();
#PutMapping(value = "/path/to/resource", consumes = MediaType.APPLICATION_JSON_VALUE)
void setResourceValue(#RequestBody String hostname);
}
The code just serializes the string to body as plain text without adding quotes (it is even stripping them). In deserialization it returns the string including quotes and it is not removing them. I know this is intended behavior but how could I achieve that client will serialize and deserialize simple String value as valid JSON?
The only workaround I was able to find was to replace String type by Jackson TextNode class. But it is not very elegant solution. It was also possible by setting JacksonEncoder instead of Spring implementation but then I loose other features.
I am passing a json object to the client side from java object with a time and value as attributes with gson
this.template.convertAndSend("/topic/123", gson.toJson(object, type));
and on the client side i have the following code where the json object data is stored in the body of the payload but I am unable to access the properties with obj.time or obj.value, it tells me undefined after it is parsed, I tried showing the entire 'obj' itself and the format seems fine however:
var subscription_callback1 = function(payload) {
var obj = JSON.parse(payload.body);
alert(obj);
};
output with alert(obj)
{"time":"3:00:34","value":"7989797"}
Nevermind solved. Since I am transfering STOMP protocol messages with the Spring 4 framework. I opted to use the Jackson2 message converter instead of directly using gson and it seems to work
#Configuration
#EnableWebSocketMessageBroker
public class MessageBrokerConfigurer extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public boolean configureMessageConverters(List<MessageConverter> messageConverters) {
messageConverters.add(new MappingJackson2MessageConverter());
return true;
}
then i directly put my java object into the send function instead of using gson to convert it as above
this.template.convertAndSend("/topic/123", event)
I have a grails object that I am converting using def json = object as JSON. After I have it converted I want to add one more property called pin to the JSON which looks like the following.
[location:[lat:23.03, lon:72.58]]
Only way to do this so far seems like following
Serialize the DomainClass to JSON using grails.converters.json
Convert the JSON to string
Create JSONBoject using the string from Step 2
Add the property
Convert it back to String
Any other way to do this using grails.converters.json? I have tried using Gson but I do not want to go that route because I am getting many Circular Reference Errors
Try this:
domainInstance.properties + [pin: pinInstance] as JSON
I recently needed to do a similar thing. Some caveats:
This is using Grails 2.4.5
I use MongoDB as a backend. As such, I created an object marshaller for MongoDB domain classes. It is printed below, and you can wrap a similar marshaller for your domain class(es):
Marshaller:
class MongodbObjectMarshaller implements ObjectMarshaller<JSON> {
#Override
boolean supports(Object o) { return o?.properties?.dbo }
#Override
void marshalObject(Object obj, JSON converter) throws
ConverterException {
Map propertiesToOutput = obj.properties.dbo
propertiesToOutput.remove("_id") //don't print org.bson.types.ObjectId
propertiesToOutput.remove("version") //don't print gorm verson column
converter.build {
_id obj.id.toString()
propertiesToOutput.each{ entry ->
"$entry.key" entry.value
}
}
}
}
What that marshaller does, it allow in JSON output any of the domain class's properties. obj.properties.dbo is special to MongoDB, but for a regular domain class, you can just grab the properties and exclude the ones you don't need.
Then in my controller, this works:
domainInstance.pin = [location:[lat:23.03, lon:72.58]]
def content = tacticalCard as JSON
because my marshaller now picks up the pin property and prints it.
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.
[{"ID":"hzQ8ll","CreationDate":"Thu, 24 Feb 2011 12:53:31 GMT","Count":6,"Name":"SOMETAG"}]
The inside is of type Tag so I just wrote this Java class:
public class Tags {
public List <Tag>tags;
}
But I get com.sun.jersey.api.client.ClientHandlerException:
org.codehaus.jackson.map.JsonMappingException: Can not deserialize instance of com.test.Tags out of START_ARRAY token
I am using Jersey with the JacksonJsonProvider like this:
ClientConfig config = new DefaultClientConfig();
config.getClasses().add(JacksonJsonProvider.class);
Then I just do a simple Jersey client call:
ClientResponse response = builder.get(ClientResponse.class);
Tags tags = response.getEntity(Tags.class);
Any ideas? Most of the time my outermost elements had a name associated to it so this is new to me. Thanks for any help
You possibly have to declare a Tag[] instead of a List<Tag>.
I had a similar issue with a different JSON library.
It seems to have to do with difficulties introspecting generic containers.
You have a strange usage of get().
http://jersey.java.net/nonav/apidocs/1.5/jersey/com/sun/jersey/api/client/UniformInterface.html#get%28java.lang.Class%29
Return and argument type should be the same.
Either:
ClientResponse resp = builder.get(ClientResponse.class);
or
Tag[] resp = builder.get(Tag[].class);
Anyway, it seems tha the problem is that your JSON data is an array and it is being deserialized into something that is not (Tags).
Try this directly:
Tag[] tags = response.getEntity(Tag[].class);