Home > Blockchain >  Java to JSON: Specify which fields get excluded for each conversion
Java to JSON: Specify which fields get excluded for each conversion

Time:04-28

As mentioned here, I know that I can convert Java objects to JSON (with Jackson)

ObjectWriter ow = new ObjectMapper().writer().withDefaultPrettyPrinter();
String json = ow.writeValueAsString(objectToBeConverted);

I know that I can exclude fields from being included in the JSON string using the @JsonIgnore annotation, but what if I want to convert the same class to JSON multiple times, but each time choosing different fields to ignore?

For example, if I have a class

class Foo {
    int a;
    int b;
    ...
}

can I do something like

Foo foo = new Foo();
String json1 = ow.writeValueAsString(foo).excludeField('b');
String json2 = ow.writeValueAsString(foo).excludeField('a');

so that the resulting strings look like

// json1
{
    a: 1234
}
// json2
{
    b: 5678
}

If Jackson can't do it, maybe Gson can? Or another library?

CodePudding user response:

There is multiple solution based on your need:

First:
You can just define two different DTO for your purpose and every time you need to each one just use it.


Second:
You can use @JsonInclude(JsonInclude.Include.NON_NULL) annotation for the properties:

class Foo {

    @JsonInclude(JsonInclude.Include.NON_NULL)
    int a;

    @JsonInclude(JsonInclude.Include.NON_NULL)
    int b;
}

P.S: You can use this annotation on class level as:

@JsonInclude(JsonInclude.Include.NON_NULL) 
class Foo {
    int a;
    int b;
}

Third:
Use can define a filter to ignore properties based on different conditions.

Define a simple class for your filter:

public class YourConditionalFilter {

    @Override
    public boolean equals(int a) {
        return a == 1234;
    }
}

And then add this filter as annotation on top of the property:

@JsonInclude(value = JsonInclude.Include.CUSTOM, valueFilter = YourConditionalFilter.class)
int a;

CodePudding user response:

You can try using different mix-in interfaces. I found two ways to do this.

  1. Use methods for reading properties. You can then create a mix-in class that only defines the properties to exclude:

    public interface ExludeA {
        @JsonIgnore
        int getA();
    }
    
  2. Use @JsonIncludeProperties to not tell which properties to exclude, but which properties to include:

    @JsonIncludeProperties({ "b", "c" })
    public interface ExludeA {
    }
    

In both cases, add that mix-in to the object mapper:

objectMapper.addMixIn(Foo.class, ExcludeA.class);

There is one very, very important thing though - you must use a new ObjectMapper for each mix-in. If you use an ObjectMapper instance to serialize a Foo instance without mix-ins, then adding the mix-in won't help. That's probably because ObjectMapper instances cache some stuff.

CodePudding user response:

Here is a simple approach if you could box all primitive type of Foo.

For example: int -> Integer, boolean -> Boolean

@JsonInclude(Include.NON_NULL)
class Foo {
    Integer a;
    Integer b;
    ...
}

Then, just make a copy of Foo and set the property which you want to ignore to null.

Foo foo = new Foo();
foo.setA(1234);
foo.setB(5678);

Foo foo1 = objectMapper.readValue(objectMapper.writeValueAsString(foo), Foo.class);  // make a copy of Foo
foo1.setB(null);  // force to ignore B
String json1 = ow.writeValueAsString(foo1); // it will be {a:1234}
  • Related