Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson only interface field deserialization

Tags:

java

json

jackson

Is it possible to deserialize only fields from interface

public interface B {
    String getB();
}

public interface A {
    String getA();
}

public class Impl implements A, B {

    @Override
    public String getA() {
        return "stringA";
    }

    @Override
    public String getB() {
        return "stringB";
    }

    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
        A implA = new Impl();
        B implB = new Impl();

        String jsonA = null;
        String jsonB = null;
        try {
            jsonA = mapper.writeValueAsString(implA);
            jsonB = mapper.writeValueAsString(implB);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        System.out.println(jsonA);
        System.out.println();
        System.out.println(jsonB);
    }
}

What i expected was

Interface A

{"a":"stringA"}

Interface B

{"b":"stringB"}

What i get is

{"a":"stringA","b":"stringB"}

{"a":"stringA","b":"stringB"}

It is possible for one interface, with this annotation @JsonSerialize(as=A.class), but it only works for the first interface. The output with @JsonSerialize is

{"a":"stringA"}

{"a":"stringA"}
like image 922
Kev Avatar asked Jun 13 '26 00:06

Kev


2 Answers

Have a look at the JsonIgnore annotation.

https://fasterxml.github.io/jackson-annotations/javadoc/2.7/com/fasterxml/jackson/annotation/JsonIgnore.html

Update

Jackson's @JsonView may fit your requirements. Below are some good articles describing the use case.

Jackson Change JsonIgnore Dynamically

http://www.baeldung.com/jackson-json-view-annotation

Code Sample

public class Sandbox {

    public static void main(String[] args) {
        ObjectMapper mapper = new ObjectMapper();
        A implA = new Impl();
        B implB = new Impl();

        String jsonA = null;
        String jsonB = null;
        try {
            ObjectWriter jsonAWriter = mapper.writerWithView(A.class);
            jsonA = jsonAWriter.writeValueAsString(implA);

            ObjectWriter jsonBWriter = mapper.writerWithView(B.class);
            jsonB = jsonBWriter.writeValueAsString(implB);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        System.out.println(jsonA);
        System.out.println();
        System.out.println(jsonB);
    }

    public interface A {
        String getA();
    }

    public interface B {
        String getB();
    }

    public static class Impl implements A, B {

        @Override
        @JsonView(A.class)
        public String getA() {
            return "stringA";
        }

        @Override
        @JsonView(B.class)
        public String getB() {
            return "stringB";
        }
    }
}

Output:

{"a":"stringA"}

{"b":"stringB"}
like image 51
Garreth Golding Avatar answered Jun 15 '26 12:06

Garreth Golding


There's no way to do that based on polymorphism principles. Below is the long proof and some alternative approach.

Your implA and implB are references to the objects of the same type. And they are serialized by the same serializer. And they both are instances of A, B and Impl at the same time. There is no way for serializer method to find out what is the type you want it to serialize as. It only can check the the real type with .class (default behavior). It also can parse annotations to find out what class you want it to be serialized as, and to check if it is really instance of that type. That's all it can.

Though it also can use some reflection to find some additional information about the object and it's class, but there's just no information about the type of the variable you declared in your main() method.

Variable type normally is not available at runtime, it is compilation time check. Though, in Java world, it may be available somewhere inside JVM, or as debug information, I'm not sure. But there's definitely no programmatic access from the callable method to a calling method.

So you can choose exactly one way how to serialize single class with single serializer, using @JsonSerialize(as=A.class) annotation.

Or you can implement your own serializer, which will use different superclasses based on some busyness logic, but not based on polymorphism.

like image 33
Alexey Mitrofanov Avatar answered Jun 15 '26 12:06

Alexey Mitrofanov



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!