3

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"}
Kev
  • 577
  • 1
  • 10
  • 29
  • I suspect there is no solution to your requirements. Even with a custom serializer, you would be either parametrizing `JsonSerializer` with `A`, `B` or `Impl` and in any case, since `writeValueAsString` doesn't take a `JsonSerializer` as parameter, your code wouldn't know what to do with the given `Impl` instance. – Mena Apr 18 '18 at 13:54
  • @ApfelPresse ... I've updated my answer to give a working example. – Garreth Golding Apr 18 '18 at 14:17
  • Write two custom Jackson serializer classes. One for interface A and one for interface B. – DwB Apr 18 '18 at 14:33

2 Answers2

1

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"}
Garreth Golding
  • 985
  • 2
  • 11
  • 19
1

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.