Spring Controller Advice to Trim JSON Data - json

I found an answer similar to this question but it isn't working when posting JSON data. I have the following:
#ControllerAdvice
public class ControllerConfig {
#InitBinder
public void initBinder ( WebDataBinder binder ) {
StringTrimmerEditor stringtrimmer = new StringTrimmerEditor(true);
binder.registerCustomEditor(String.class, stringtrimmer);
}
}
I know that the code is being reached during binding via debugging but when I pass in data like:
{ "companyId": " ABC "}
ABC isn't actually being trimmed during binding. My guess is that this only works with request params and not raw JSON bodies but not sure about that. If that is the case, is there something I can do that is similar?

Create this JsonDeserializer
public class WhiteSpaceRemovalDeserializer extends JsonDeserializer<String> {
#Override
public String deserialize(JsonParser jp, DeserializationContext ctxt) {
// This is where you can deserialize your value the way you want.
// Don't know if the following expression is correct, this is just an idea.
return jp.getCurrentToken().asText().trim();
}
}
and set this to your property
#JsonDeserialize(using=WhiteSpaceRemovalSerializer.class)
public void setAString(String aString) {
// body
}

Try this,
Create a class.
Annotate the class with #JsonComponent
extend the JsonDeserializer
and, add your trimming logic in the overridden method,
this will automatically trim the whitespaces in the json request, when it hits the controller, no external properties needed to activate this.
#JsonComponent
public class WhiteSpaceRemover extends JsonDeserializer<String> {
#Override
public String deserialize(JsonParser arg0, DeserializationContext arg1)
throws IOException, JsonProcessingException {
return arg0.getValueAsString().trim();
}
}

Related

How to deserialize single json property into multiple Java fields (if possible with converter)

Having this class:
#Getter
#Setter
public class Result {
private String positionText;
private Integer positionNumber;
.. many many other properties ..
}
and deserializing this json:
[
{
"position": "1",
.. many many other properties ..
},
{
"position": "FOO",
.. many many other properties ..
},
..
}
how can the position json property deserialized into both the positionText and positionNumber Java fields?
public abstract class ResultMixIn {
#JsonProperty("position")
abstract String getPositionText();
#JsonProperty("position")
abstract Integer getPositionNumber();
}
but this gives a:
Conflicting getter definitions for property "position": com.example.domain.Result#getPositionText() vs com.example.domain.Result#getPositionNumber()
Also changing the abstract getters to setters does not make a difference.
If possible I would like to avoid a fully fledged ResultDeserializer extending StdDeserializer as the Result class has many more properties which I would prefer not to deserialize "by hand".
PS: I'm not concerned about serializing. I'm only deserializing the model.
First you need to annotate the properties of the Result class,
so that Jackson will deserialize the positionText property,
but not the positionNumber.
You will do the latter by yourself in a taylor-made deserializer.
#Getter
#Setter
public class Result {
#JsonProperty("position")
private String positionText;
#JsonIgnore
private Integer positionNumber;
.. many many other properties ..
}
By default Jackson would use a BeanDeserializer for deserializing Result objects.
But you want a slightly modified implementation of this deserializer.
The rest of this answer is largely an adaptation of the accepted answer given to
the question How do I call the default deserializer from a custom deserializer in Jackson.
As usual your deserializer extends from StdDeserializer<Result>,
but it also implements the ResolvableDeserializer interface.
In the deserialize method most of the work is delegated to the default deserializer
(in this case a BeanDeserializer) which we got from Jackson.
We only add a small extra logic for setting the positionNumber property
based on the positionText property.
public class ResultDeserializer extends StdDeserializer<Result> implements ResolvableDeserializer {
private final JsonDeserializer<?> defaultDeserializer;
public ResultDeserializer(JsonDeserializer<?> defaultDeserializer) {
super(Result.class);
this.defaultDeserializer = defaultDeserializer;
}
#Override
public void resolve(DeserializationContext ctxt) throws JsonMappingException {
if (defaultDeserializer instanceof ResolvableDeserializer) {
// We need to resolve the default deserializer, or else it won't work properly.
((ResolvableDeserializer) defaultDeserializer).resolve(ctxt);
}
}
#Override
public Result deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
// let defaultDeserializer do the work:
Result result = (Result) defaultDeserializer.deserialize(p, ctxt);
// here you do your custom logic:
String positionText = result.getPositionText();
if (positionText != null) {
try {
result.setPositionNumber(Integer.valueOf(positionText));
} catch(NumberFormatException e) {
// positionText is not a valid integer
}
}
return result;
}
}
Finally you need to tell Jackson that you want the above ResultDeserializer
to be used for deserializing Result objects.
This is done by the following customization of the ObjectMapper,
which will wrap your ResultDeserializer around Jackson's
default deserializer, only if a Result object is to be deserialized:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new SimpleModule()
.setDeserializerModifier(new BeanDeserializerModifier() {
#Override
public JsonDeserializer<?> modifyDeserializer(DeserializationConfig config,
BeanDescription beanDesc, JsonDeserializer<?> deserializer) {
if (Result.class == beanDesc.getBeanClass())
return new ResultDeserializer(deserializer); // your deserializer
return deserializer;
}
}));
Then you can deserialize your JSON content as usual, for example:
File file = new File("example.json");
List<Result> results = objectMapper.readValue(file, new TypeReference<List<Result>>() {});

Is it possible to pass a java.util.Stream to Gson?

I'm currently working on a project where I need to fetch a large amount of data from the Database and parse it into a specific Json format, I already have built my custom Serializers and Its working properly when i pass a List to Gson. But as I was already working with Streams from my JPA Layer, I thought I could pass the Stream down to the Gson parser so that it could transform it directly to my Json data. But I'm getting an empty Json object instead of a correctly populated one.
So, if anyone could point to me a way to make Gson work with Java 8 Streams or if this isn't possible currently.. i could not find anything on Google, so i came to Stackoverflow.
You could use JsonWriter to streaming your data to output stream:
public void writeJsonStream(OutputStream out, Stream<DataObject> data) throws IOException {
try(JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8"))) {
writer.setIndent(" ");
writer.beginArray();
data.forEach(d -> {
d.beginObject();
d.name("yourField").value(d.getYourField());
....
d.endObject();
});
writer.endArray();
}
}
Note that you're in charge of controling the json structure.
That is, if your DataObject contains nested Object, you have to write beginObject()/endObject() respectively. The same goes for nested array.
It is not as trivial as one would expect, but it can be done in a generic way.
When you look into the Javadoc to TypeAdapterFactory, they provide a very simplistic way of writing a TypeAdapterFactory for a custom type. Alas, it does not work as expected because of problems with element type detection. The proper way to do this can be found in Gson-internal CollectionTypeAdapterFactory. It is quite complex, but taking what's necessary one can come up with something like that:
final class StreamTypeAdapterFactory implements TypeAdapterFactory {
#SuppressWarnings("unchecked")
#Override
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
Type type = typeToken.getType();
Class<? super T> rawType = typeToken.getRawType();
if (!Stream.class.isAssignableFrom(rawType)) {
return null;
}
Type elementType = ExtraGsonTypes.getStreamElementType(type, rawType);
TypeAdapter<?> elementAdapter = gson.getAdapter(TypeToken.get(elementType));
return (TypeAdapter<T>) new StreamTypeAdapter<>(elementAdapter);
}
private static class StreamTypeAdapter<E> extends TypeAdapter<Stream<E>> {
private final TypeAdapter<E> elementAdapter;
StreamTypeAdapter(TypeAdapter<E> elementAdapter) {
this.elementAdapter = elementAdapter;
}
public void write(JsonWriter out, Stream<E> value) throws IOException {
out.beginArray();
for (E element : iterable(value)) {
elementAdapter.write(out, element);
}
out.endArray();
}
public Stream<E> read(JsonReader in) throws IOException {
Stream.Builder<E> builder = Stream.builder();
in.beginArray();
while (in.hasNext()) {
builder.add(elementAdapter.read(in));
}
in.endArray();
return builder.build();
}
}
private static <T> Iterable<T> iterable(Stream<T> stream) {
return stream::iterator;
}
}
The ExtraGsonTypes is a special class that I used to circumvent package-private access to $Gson$Types.getSupertype method. It's a hack that works if you're not using JDK 9's modules - you simply place this class in the same package as $Gson$Types:
package com.google.gson.internal;
import java.lang.reflect.*;
import java.util.stream.Stream;
public final class ExtraGsonTypes {
public static Type getStreamElementType(Type context, Class<?> contextRawType) {
return getContainerElementType(context, contextRawType, Stream.class);
}
private static Type getContainerElementType(Type context, Class<?> contextRawType, Class<?> containerSupertype) {
Type containerType = $Gson$Types.getSupertype(context, contextRawType, containerSupertype);
if (containerType instanceof WildcardType) {
containerType = ((WildcardType)containerType).getUpperBounds()[0];
}
if (containerType instanceof ParameterizedType) {
return ((ParameterizedType) containerType).getActualTypeArguments()[0];
}
return Object.class;
}
}
(I filed an issue about that in GitHub)
You use it in the following way:
Gson gson = new GsonBuilder()
.registerTypeAdapterFactory(new StreamTypeAdapterFactory())
.create();
System.out.println(gson.toJson(Stream.of(1, 2, 3)));

Add new line at the end of Jersey generated JSON

I have a Jersey (1.x) based REST service. It uses Jackson 2.4.4 to generate JSON responses. I need to add a newline character at the end of response (cURL users complain that there's no new line in responses). I am using Jersey pretty-print feature (SerializationFeature.INDENT_OUTPUT).
current: {\n "prop" : "value"\n}
wanted: {\n "prop" : "value"\n}\n
I tried using a custom serializer. I need to add \n only at the end of the root object. Serializer is defined per data type, which means, if an instance of such class is nested in a response, I will get \n in the middle of my JSON.
I thought of subclassing com.fasterxml.jackson.core.JsonGenerator.java, overriding close() where i'd add writeRaw('\n'), but that feels very hacky.
Another idea would be to add Servlet filter which would re-write the response from Jersey Filter, adding the \n and incrementing the contentLenght by 1. Seems not only hacky, but also inefficient.
I could also give up Jersey taking care of serializing the content and do ObjectMapper.writeValue() + "\n", but this is quite intrusive to my code (need to change many places).
What is the clean solution for that problem?
I have found these threads for the same problem, but none of them provides solution:
http://markmail.org/message/nj4aqheqobmt4o5c
http://jackson-users.ning.com/forum/topics/add-newline-after-object-serialization-in-jersey
Update
Finally I went for #arachnid's solution with NewlineAddingPrettyPrinter (also bumper Jackson version to 2.6.2). Sadly, it does not work out of the box with Jaskson as JAX-RS Json provider. Changed PrettyPrinter in ObjectMapper does not get propagated to JsonGenerator (see here why). To make it work, I had to add ResponseFilter which adds ObjectWriterModifier (now I can easily toggle between pretty-print and minimal, based on input param ):
#Provider
public class PrettyPrintFilter extends BaseResponseFilter {
public ContainerResponse filter(ContainerRequest request, ContainerResponse response) {
ObjectWriterInjector.set(new PrettyPrintToggler(true));
return response;
}
final class PrettyPrintToggler extends ObjectWriterModifier {
private static final PrettyPrinter NO_PRETTY_PRINT = new MinimalPrettyPrinter();
private final boolean usePrettyPrint;
public PrettyPrintToggler(boolean usePrettyPrint) {
this.usePrettyPrint = usePrettyPrint;
}
#Override
public ObjectWriter modify(EndpointConfigBase<?> endpoint, MultivaluedMap<String, Object> responseHeaders,
Object valueToWrite, ObjectWriter w, JsonGenerator g) throws IOException {
if (usePrettyPrint) g.setPrettyPrinter(new NewlineAddingPrettyPrinter());
else g.setPrettyPrinter(NO_PRETTY_PRINT);
return w;
}
}
}
Actually, wrapping up (not subclassing) JsonGenerator isn't too bad:
public static final class NewlineAddingJsonFactory extends JsonFactory {
#Override
protected JsonGenerator _createGenerator(Writer out, IOContext ctxt) throws IOException {
return new NewlineAddingJsonGenerator(super._createGenerator(out, ctxt));
}
#Override
protected JsonGenerator _createUTF8Generator(OutputStream out, IOContext ctxt) throws IOException {
return new NewlineAddingJsonGenerator(super._createUTF8Generator(out, ctxt));
}
}
public static final class NewlineAddingJsonGenerator extends JsonGenerator {
private final JsonGenerator underlying;
private int depth = 0;
public NewlineAddingJsonGenerator(JsonGenerator underlying) {
this.underlying = underlying;
}
#Override
public void writeStartObject() throws IOException {
underlying.writeStartObject();
++depth;
}
#Override
public void writeEndObject() throws IOException {
underlying.writeEndObject();
if (--depth == 0) {
underlying.writeRaw('\n');
}
}
// ... and delegate all the other methods of JsonGenerator (CGLIB can hide this if you put in some time)
}
#Test
public void append_newline_after_end_of_json() throws Exception {
ObjectWriter writer = new ObjectMapper(new NewlineAddingJsonFactory()).writer();
assertThat(writer.writeValueAsString(ImmutableMap.of()), equalTo("{}\n"));
assertThat(writer.writeValueAsString(ImmutableMap.of("foo", "bar")), equalTo("{\"foo\":\"bar\"}\n"));
}
A servlet filter isn't necessarily too bad either, although recently the ServletOutputStream interface has been more involved to intercept properly.
I found doing this via PrettyPrinter problematic on earlier Jackson versions (such as your 2.4.4), in part because of the need to go through an ObjectWriter to configure it properly: only fixed in Jackson 2.6. For completeness, this is a working 2.5 solution:
#Test
public void append_newline_after_end_of_json() throws Exception {
// Jackson 2.6:
// ObjectMapper mapper = new ObjectMapper()
// .setDefaultPrettyPrinter(new NewlineAddingPrettyPrinter())
// .enable(SerializationFeature.INDENT_OUTPUT);
// ObjectWriter writer = mapper.writer();
ObjectMapper mapper = new ObjectMapper();
ObjectWriter writer = mapper.writer().with(new NewlineAddingPrettyPrinter());
assertThat(writer.writeValueAsString(ImmutableMap.of()), equalTo("{}\n"));
assertThat(writer.writeValueAsString(ImmutableMap.of("foo", "bar")),
equalTo("{\"foo\":\"bar\"}\n"));
}
public static final class NewlineAddingPrettyPrinter
extends MinimalPrettyPrinter
implements Instantiatable<PrettyPrinter> {
private int depth = 0;
#Override
public void writeStartObject(JsonGenerator jg) throws IOException, JsonGenerationException {
super.writeStartObject(jg);
++depth;
}
#Override
public void writeEndObject(JsonGenerator jg, int nrOfEntries) throws IOException, JsonGenerationException {
super.writeEndObject(jg, nrOfEntries);
if (--depth == 0) {
jg.writeRaw('\n');
}
}
#Override
public PrettyPrinter createInstance() {
return new NewlineAddingPrettyPrinter();
}
}
Not yet tested but the following should work:
public class MyObjectMapper extends ObjectMapper {
_defaultPrettyPrinter = com.fasterxml.jackson.core.util.MinimalPrettyPrinter("\n");
// AND/OR
#Override
protected PrettyPrinter _defaultPrettyPrinter() {
return new com.fasterxml.jackson.core.util.MinimalPrettyPrinter("\n");
}
}
public class JerseyConfiguration extends ResourceConfig {
...
MyObjectMapper mapper = new MyObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT); //enables pretty printing
// create JsonProvider to provide custom ObjectMapper
JacksonJaxbJsonProvider provider = new JacksonJaxbJsonProvider();
provider.setMapper(mapper);
register(provider); //register so that jersey use it
}
Do not know if this is the "cleanest" solution but it feels less hacky than the others.
Should produce something like
{\n "root" : "1"\n}\n{\n "root2" : "2"\n}
But it seems that does not work if there is only one root element.
Idea is from https://gist.github.com/deverton/7743979

sequentially deserialize using Jackson

I have a value object serialized and deserialized using Jackson.
The VO has two fields: x and y. But invoking setY makes sense only when x is set. Is there any way I can make sure that setX is invoked earlier than setY during de-serialization?
You can do it only by implementing custom deserializer for your POJO (VO) class. Let assume that you POJO class looks like this:
class Point {
private int x;
private int y;
//getters, setters, toString
}
Now, you can implement deserializer. You can do it in this way:
class PointJsonDeserializer extends JsonDeserializer<Point> {
#Override
public Point deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
InnerPoint root = jp.readValueAs(InnerPoint.class);
Point point = new Point();
point.setX(root.x);
point.setY(root.y);
return point;
}
private static class InnerPoint {
public int x;
public int y;
}
}
After that, you have to tell Jackson to use above deserializer. For example, in this way:
#JsonDeserialize(using = PointJsonDeserializer.class)
class Point {
...
}
For me, your setY brakes setter method responsibility. You should avoid situation like that where you hide class logic in setter method. Better solution is creating new method for calculations:
point.setX(10);
point.setY(11);
point.calculateSomething();

fromJson GSON Complex Class

I have the following code.
public class SomeClass {
private List<SomeOtherClass> referrals;
public List<SomeOtherClass> getReferrals() {
return referrals;
}
public void setReferrals( List<SomeOtherClass> referrals) {
this.referrals = referrals;
}
}
I have a json that I read from the wire. It is correctly formatted. I use GSON
My question is :
when I do fromJson(jsonString,SomeClass.class);
it gives an exception.
If I don't use List<SomeOtherClass> but instead use List<String> for referrals.
(in other word a primitive)
And iterate over each String and create SomeOtherClass object it works fine.
Why can't I just use fromJson(jsonString,SomeClass.class);