The input stream I am parsing with Jackson contains latitude and longitude values such as here:
{
"name": "product 23",
"latitude": "52,48264",
"longitude": "13,31822"
}
For some reason the server uses commas as the decimal separator which produces an InvalidFormatException
. Since I cannot change the server output format I would like to teach Jackson's ObjectMapper
to handle those cases. Here is the relevant code:
public static Object getProducts(final String inputStream) {
ObjectMapper objectMapper = new ObjectMapper();
try {
return objectMapper.readValue(inputStream,
new TypeReference<Product>() {}
);
} catch (UnrecognizedPropertyException e) {
e.printStackTrace();
} catch (InvalidFormatException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (JsonParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
And here is the POJO:
import com.fasterxml.jackson.annotation.JsonProperty;
public class Product {
@JsonProperty("name")
public String name;
@JsonProperty("latitude")
public float latitude;
@JsonProperty("longitude")
public float longitude;
}
How can I tell Jackson that those coordinate values come with a German locale?
I suppose a custom deserializer for the specific fields as discussed here would be the way to go. I drafted this:
public class GermanFloatDeserializer extends JsonDeserializer<Float> {
@Override
public Float deserialize(JsonParser parser, DeserializationContext context)
throws IOException {
// TODO Do some comma magic
return floatValue;
}
}
Then the POJO would look like this:
import com.fasterxml.jackson.annotation.JsonProperty;
public class Product {
@JsonProperty("name")
public String name;
@JsonDeserialize(using = GermanFloatDeserializer.class, as = Float.class)
@JsonProperty("latitude")
public float latitude;
@JsonDeserialize(using = GermanFloatDeserializer.class, as = Float.class)
@JsonProperty("longitude")
public float longitude;
}
With all respect to accepted answer, there is a way to get rid of those
@JsonDeserialize
annotations.You need to register the custom deserializer in the ObjectMapper.
Following the tutorial from official web-site you just do something like:
If you're using Spring Boot there is a simpler method. Just define the Jackson2ObjectMapperBuilder bean somewhere in your Configuration class:
and add the custom
HttpMessageConverter
to the list ofWebMvcConfigurerAdapter
message converters:A more general solution than the other proposed answers, which require registering individual deserializers for each type, is to provide a customized
DefaultDeserializationContext
toObjectMapper
.The following implementation (which is inspired by
DefaultDeserializationContext.Impl
) worked for me:Now set up your object mapper with your desired locale:
If you use Spring
RestTemplate
, you can set it up to useobjectMapper
like so:Note that the value must be represented as a string in the JSON document (i.e.
{"number": "2,2"}
), since e.g.{"number": 2,2}
is not valid JSON and will fail to parse.I came up with the following solution:
...
Still I wonder why I it does not work when I specify the return value class as
as = Float.class
as can be found in the documentation ofJsonDeserialize
. It reads as if I am supposed to use one or the other but not both. Whatsoever, the docs also claim thatas =
will be ignored whenusing =
is defined: