I am fetching some data via a REST service, but I am getting this error when deserializing the response :
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "ResultSet Output" (class com.HolderCollectionWrapper), not marked as ignorable (one known property: "holders"]) at [Source: java.io.ByteArrayInputStream#74efa7bd; line: 1, column: 22] (through reference chain: com.HolderCollectionWrapper["ResultSet Output"])
This is my code :
response = restTemplate.exchange(requestUrl, HttpMethod.GET, request, HolderCollectionWrapper.class);
public class HolderCollectionWrapper {
#SerializedName("ResultSet Output")
private List<Holder> holders;
public List<Holder> getHolders() {
return holders;
}
public void setHolders(List<Holder> holders) {
this.holders = holders;
}
}
This is the JSON I am getting :
{
"ResultSet Output": [
{...}, {...}, {...}
]
}
Despite the #SerializedName("ResultSet Output"), it's not working, why ?
#SerializedName is a gson annotation and you are using jackson library for serialization.
The jackson annotation for field name is #JsonProperty
Try:
#JsonProperty("ResultSet Output")
private List<Holder> holders;
This happens because the SerializedName("ResultSet Output") gson annotation indicates that the holders will be serialized with the ResultSet Output name like the json example you post; to deserialize it with jackson you have to use the JsonProperty annotation, specifying the ResultSet Output name applied on the setter to avoid possible conflicts with the gson library used for serialization:
public class HolderCollectionWrapper {
#SerializedName("ResultSet Output")
private List<Holder> holders;
public List<Holder> getHolders() {
return holders;
}
#JsonProperty("ResultSet Output")
public void setHolders(List<Holder> holders) {
this.holders = holders;
}
}
Related
I serialize this kind of object:
public class MyObject implements Serializable {
private String type;
...
private String[] target;
//getters and setters
}
But when I try to deserialize MyObject I get an error because of the target array.
java.lang.RuntimeException: com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_ARRAY token
at [Source: UNKNOWN; line: -1, column: -1] (through reference chain: java.util.ArrayList[0]->MyObject["target"])
...
How can I deserialize an array ?
I finally found the problem. I did not see I had 2 setters in the class. Jackson was probably using the wrong one.
I just had to put the annotation #JsonSetter("target") above the setter which accept an array to tell Jackson to use the good one.
public void setTarget(String target) {
this.target = new String[]{target};
}
#JsonSetter("target")
public void setTarget(String[] target) {
this.target = target;
}
I am using com.fasterxml.jackson.databind in a spring boot application. When I send a request to my endpoint I receive the following exception:
com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of
org.pacakge.domain.controller.Mycontroller (although at least one Creator exists): cannot
deserialize from Object value (no delegate- or property-based Creator)\n at
[Source: (PushbackInputStream); line: 2, column: 3] Is the body of the request formatted correctly?
My controller processes a request body that has the following structure:
{
"portalId": 123,
"objectType": "TYPE",
"objectTypeId": "0-3",
"objectId": 123,
"properties": { ... }
}
The only property that I need is objectId. I've constructed a class to process this object like so:
#lombok.Value
private static class MyObject {
#JsonAlias("objectId")
private final String dealId;
}
I've designed a controller that looks like this
#Slf4j
#RestController
#RequestMapping(path = "/entrypoint")
public class MyController {
#Autowired
public MyController(){}
/**
* REST endpoint handles MyObject
*/
#PostMapping(value = "/endpoint")
public void handleRequest(
#Valid #RequestBody MyObject command
) {
log.debug(command.getDealId());
}
#lombok.Value
private static class MyObject {
#JsonAlias("objectId")
private final String dealId;
}
}
What is interesting about this problem is that my request is processed just fine if I change MyObject to the following structure:
#lombok.Value
private static class MyObject {
#JsonAlias("objectId")
private final String dealId;
private final JSONObject properties; // TODO we shouldn't need this. Fix.
}
I cannot seem to figure out what the issue is. I would love some help on this problem. Maybe there is annotation that I am missing? I am hoping someone else has experienced this issue. I haven't found any information on it by just searching the web.
I added the following line to lombok.config in the root directory of the project:
lombok.anyConstructor.addConstructorProperties=true
And after that managed to deserialize your JSON using this DTO using #JsonIgnoreProperties annotation:
#Value
#JsonIgnoreProperties(ignoreUnknown = true)
public class MyObject {
#JsonProperty("objectId")
String dealId;
}
I want to integrate vavr validation library in my command dto's in a way that when command dto is deserialized from request, return type of the static factory will be Try but jackson is throwing following error :
Type definition error: [simple type, class com.foo.command.FooCommand]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of com.foo.command.FooCommand (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
Here is FooCommand
#AllArgsConstructor(access = AccessLevel.PRIVATE)
public final class FooCommand {
private String foo;
private String bar;
#JsonCreator
public static Try<FooCommand> of(
#JsonProperty("foo") String foo,
#JsonProperty("bar") String bar
) {
return Try.of(() -> {
//Validate values
});
}
}
I am using spring 5 and it's annotated to deserialize request body automatically into controller parameter.
Is something like this possible ? Thanks in advance.
I had a similar problem that I fixed by using Converters: Using Jackson, how can I deserialize values using static factory methods that return wrappers with a generic type?
I haven't yet found how to apply the converters automatically, so you have to annotate every occurrence of the wrapped type in your requests.
public class Request {
#JsonDeserialize(converter = FooCommandConverter.class)
Try<FooCommand> command;
}
You can write a Converter like so:
public class FooCommandConverter
extends StdConverter<FooCommandConverter.DTO, Try<FooCommand>> {
#Override
public Try<FooCommand> convert(FooCommandConverter.DTO dto) {
return FooCommand.of(
dto.foo,
dto.bar
);
}
public static class DTO {
public String foo;
public String bar;
}
}
I have this JAXB-annotated class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
public class SomeClass {
#XmlAttribute
public String value;
}
Based on this class, a JSON document was produced using jersey-json (via com.sun.jersey.api.json.JSONJAXBContext):
{
"#value":"someValue"
}
Note that jersey decided to use #value as tag name (and not simply value), probably in order to honour the #XmlAttribute annotation.
Now the task is to read this json document using jackson-json and produce an instance of the JAXB annotated class:
ObjectMapper mapper = new ObjectMapper();
JaxbAnnotationIntrospector introspector = new JaxbAnnotationIntrospector(mapper.getTypeFactory());
DeserializationConfig deserConfig = mapper.getDeserializationConfig().with(introspector);
mapper.setConfig(deserConfig);
SerializationConfig serConfig = mapper.getSerializationConfig().with(introspector);
mapper.setConfig(serConfig);
mapper.readValue(jsonFile, SomeClass.class);
This fails with the following exception:
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "#value" (class test.jersey.vs.jackson.SomeClass), not marked as ignorable (one known property: "value"])
at [Source: C:\Users\AppData\Local\Temp\junit5080915042527904512\json.txt; line: 1, column: 12] (through reference chain: test.jersey.vs.jackson.SomeClass["#value"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:62)
at com.fasterxml.jackson.databind.DeserializationContext.handleUnknownProperty(DeserializationContext.java:834)
at com.fasterxml.jackson.databind.deser.std.StdDeserializer.handleUnknownProperty(StdDeserializer.java:1093)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownProperty(BeanDeserializerBase.java:1477)
at com.fasterxml.jackson.databind.deser.BeanDeserializerBase.handleUnknownVanilla(BeanDeserializerBase.java:1455)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:282)
at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:140)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3798)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2740)
My question now is whether there is a way to tell jackson to associate the #value tag from the JSON document with the value field of the class.
I tried specifying a PropertyNamingStrategy, but that was never called during deserialization.
PropertyNamingStrategy pns = new PropertyNamingStrategy() {
#Override
public String nameForField(MapperConfig<?> config, AnnotatedField field, String defaultName) {
if (field.hasAnnotation(XmlAttribute.class)) {
if (defaultName.startsWith("#")) {
return defaultName.substring(1);
}
}
return super.nameForField(config, field, defaultName);
}
};
DeserializationConfig deserConfig = mapper.getDeserializationConfig().with(introspector).with(pns);
mapper.setConfig(deserConfig);
In a Spring Boot/Spring Data Rest project i have issues to use a custom JsonSerializer<Set<Object>> on a #OneToMany property. When i do an HTTP GET /collection request i have the following error:
Failed to write HTTP message:
org.springframework.http.converter.HttpMessageNotWritableException:
Could not write content: Can not override serializer (through
reference chain:
org.springframework.hateoas.Resources["_embedded"]->java.util.UnmodifiableMap["analogParameters"]->java.util.ArrayList[0]);
nested exception is
com.fasterxml.jackson.databind.JsonMappingException: Can not override
serializer (through reference chain:
org.springframework.hateoas.Resources["_embedded"]->java.util.UnmodifiableMap["analogParameters"]->java.util.ArrayList[0])
Below is an extract of my entity class:
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="output_parameter_id")
#JsonSerialize(using=InputParametersSerializer.class)
//#Transcient
private Set<InputParameter> inputParameters = new HashSet<InputParameter>();
public Set<InputParameter> getInputParameters() {
return inputParameters;
}
public void setInputParameters(Set<InputParameter> inputParameters) {
this.inputParameters = inputParameters;
}
And the JsonSerializer<Set<InputParameter>>
public class InputParametersSerializer
extends JsonSerializer<Set<InputParameter>> {
static final long serialVersionUID = 123L;
public void serialize (Set<InputParameter> ips, JsonGenerator jg,
SerializerProvider sp)
throws IOException {
jg.writeString("Yeah");
}
}
If i remove #OneToMany and define the property as #transient it works as expected.
InputParameter entity has no Repository associated (it is not exported as a rest resource).
How can a make use of a JsonSerializer on a #OneToMany property?
I ran into a very similar issue while using Spring Boot 2.1.0. Adding a custom serializer, both with using and keyUsing, works fine, but a custom deserializer with a #OneToMany annotated field throws out the same JsonMappingException: Can not override serializer message you got, while with an #ElementCollection it just plain gets ignored. I suspect Spring Data Rest does some undocumented magic in order to take care of the (de)serialization of these kinds of fields that does not play nice with the addition of a custom deserializer. My workaround to this was adding an extra JSON field through an annotated getter and setter. With your example, it would look like:
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="output_parameter_id")
private Set<InputParameter> inputParameters = new HashSet<InputParameter>();
public Set<InputParameter> getInputParameters() {
return inputParameters;
}
public void setInputParameters(Set<InputParameter> inputParameters) {
this.inputParameters = inputParameters;
}
#JsonSerialize(using=InputParametersSerializer.class)
public Set<InputParameter> getInputParametersSet() {
return getInputParameters();
}
#JsonDeserialize(using=InputParametersDeserializer.class)
public void setInputParametersSet(Set<InputParameter> inputParameters) {
setInputParameters(inputParameters);
}
Which will output something like
{
...
"inputParameters" : ...,
"inputParametersSet" : ...,
...
}
While not ideal, serialization and deserialization of this field works as expected.
alternatively, in order to keep the field name, a similar workaround worked with #ElementCollection but not with #OneToMany:
#OneToMany(cascade=CascadeType.ALL)
#JoinColumn(name="output_parameter_id")
#JsonIgnore
private Set<InputParameter> inputParameters = new HashSet<InputParameter>();
public Set<InputParameter> getInputParameters() {
return inputParameters;
}
public void setInputParameters(Set<InputParameter> inputParameters) {
this.inputParameters = inputParameters;
}
#JsonProperty("inputParameters")
#JsonSerialize(using=InputParametersSerializer.class)
public Set<InputParameter> getInputParametersSet() {
return getInputParameters();
}
#JsonProperty("inputParameters")
#JsonDeserialize(using=InputParametersDeserializer.class)
public void setInputParametersSet(Set<InputParameter> inputParameters) {
setInputParameters(inputParameters);
}
In the end I had to go with the first approach.