42

I have a class and there are variables inside it as well. Sometimes I want to ignore some fields and sometimes not when deserializing (maybe at serializing too). How can I do it at Jackson?

kamaci
  • 72,915
  • 69
  • 228
  • 366

4 Answers4

25

For serialization, "filtering properties" blog entry should help. Deserialization side has less support, since it is more common to want to filter out stuff that is written.

One possible approach is to sub-class JacksonAnnotationIntrospector, override method(s) that introspect ignorability of methods (and/or fields) to use whatever logic you want.

It might also help if you gave an example of practical application, i.e what and why you are trying to prevent from being deserialized.

StaxMan
  • 113,358
  • 34
  • 211
  • 239
  • Here is an explanation: http://www.jroller.com/RickHigh/entry/filtering_json_feeds_from_spring I don't use Roo and aspectj code give error at my Intellij IDEA8(thisJoinPoint and proceed methods can not recognized). It would be great if I could implement it as annotation as like described. – kamaci Nov 21 '11 at 08:09
  • I have a Spring 3 REST application. I have a bean at my server side and I list them at client. However it has many fields and I dın't list every field of my bean at table. However at another page I list all the fields of my bean at another table. So my purpose is that I don't want to send all information to client side for efficiency. – kamaci Nov 21 '11 at 08:15
  • Ok: but just to be clear -- when sending things, you are generally talking about serialization; deserialization is the reverse (reading JSON into objects). So perhaps you are looking for serialization feature instead? If so, link I mentioned would be very useful? – StaxMan Nov 21 '11 at 18:34
  • serialization is so important for me, you are right. I read that link and I will try to implement it, thanks for your help. – kamaci Nov 21 '11 at 18:36
  • The link is superb! I find Fully dynamic filtering: `@JsonFilter` extrmemely well suited to my use case where I want more control in terms of fetching (serializing) but not beyond a certain level as it ends up getting recursively fetched. ORMs tend to be like that. – absin Sep 06 '18 at 17:16
4

You might want to use JsonViews ( took it originally from http://wiki.fasterxml.com/JacksonJsonViews - broken now - web archive link: https://web.archive.org/web/20170831135842/http://wiki.fasterxml.com/JacksonJsonViews )

Quoting it:

First, defining views means declaring classes; you can reuse existing ones, or just create bogus classes -- they are just view identifiers with relationship information (child inherits view membership from parents):

 // View definitions:
  class Views {
            static class Public { }
            static class ExtendedPublic extends PublicView { }
            static class Internal extends ExtendedPublicView { }
  }

  public class Bean {
            // Name is public
            @JsonView(Views.Public.class) String name;
            // Address semi-public
            @JsonView(Views.ExtendPublic.class) Address address;
            // SSN only for internal usage
            @JsonView(Views.Internal.class) SocialSecNumber ssn;
  }

With such view definitions, serialization would be done like so:

 // short-cut:
  objectMapper.writeValueUsingView(out, beanInstance, ViewsPublic.class);

  // or fully exploded:
  objectMapper.getSerializationConfig().setSerializationView(Views.Public.class);
  // (note: can also pre-construct config object with 'mapper.copySerializationConfig'; reuse)
  objectMapper.writeValue(out, beanInstance); // will use active view set via Config

  // or, starting with 1.5, more convenient (ObjectWriter is reusable too)
  objectMapper.viewWriter(ViewsPublic.class).writeValue(out, beanInstance);
and result would only contain 'name', not 'address' or 'ssn'.
João Antunes
  • 811
  • 9
  • 16
0

I searched the entire web (yes I did) to find the answer. then I wrote something on my own.

I'm working with Jackson ion deserialisation. I wrote a custom reader that ignores the fields dynamically.

You can do the same thing for json deserialisation.

Lets assume an entity like this.

User {
    id
    name
    address {
       city
    }
}

Create a tree structure to represent field selection.

public class IonField {

    private final String name;
    private final IonField parent;
    private final Set<IonField> fields = new HashSet<>();

    // add constructs and stuff
}

Custom Ion Reader extending from amazon ion-java https://github.com/amzn/ion-java

public class IonReaderBinaryUserXSelective extends IonReaderBinaryUserX {

    private IonField _current;
    private int hierarchy = 0;

    public IonReaderBinaryUserXSelective(byte[] data, int offset, int length,
                                         IonSystem system, IonField _current) {
        super(system, system.getCatalog(), UnifiedInputStreamX.makeStream(data, offset, length));
        this._current = _current;
    }

    @Override
    public IonType next() {
        IonType type = super.next();

        if (type == null) {
            return null;
        }

        String file_name = getFieldName();

        if (file_name == null || SystemSymbols.SYMBOLS.equals(file_name)) {
            return type;
        }

        if (type == IonType.STRUCT || type == IonType.LIST) {
            IonField field = _current.getField(getFieldName());
            if (field != null) {
                this._current = field;
                return type;
            } else {
                super.stepIn();
                super.stepOut();
            }
            return next();
        } else {
            if (this._current.contains(file_name)) {
                return type;
            } else {
                return next();
            }
        }
    }

    @Override
    public void stepIn() {
        hierarchy = (hierarchy << 1);
        if (getFieldName() != null && !SystemSymbols.SYMBOLS.equals(getFieldName())) {
            hierarchy = hierarchy + 1;
        }
        super.stepIn();
    }

    @Override
    public void stepOut() {
        if ((hierarchy & 1) == 1) {
            this._current = this._current.getParent();
        }
        hierarchy = hierarchy >> 1;
        super.stepOut();
    }

Construct dynamic view. This Tree dynamically created and passed to the reader to deserialise.

Let's say we only need city inside the address.

IonField root = new IonField("user", null);

IonField address = new IonField("address", root);
IonField city = new IonField("city", address);
address.addChild(city);

root.addChild(id);


//now usual stuff.

IonFactory ionFactory = new IonFactory();
IonObjectMapper mapper = new IonObjectMapper(ionFactory);

File file = new File("file.bin"); // ion bytes

byte[] ionData =  Files.readAllBytes(file.toPath());

IonSystem ionSystem = IonSystemBuilder.standard().build();
IonReader ionReader = new IonReaderBinaryUserXSelective(ionData, 0, ionData.length, ionSystem, root);

User user = mapper.readValue(ionReader, User.class);

Satthy
  • 109
  • 1
  • 3
  • 10
  • this could help understand. https://amzn.github.io/ion-docs/guides/cookbook.html#down-converting-to-json – Satthy Aug 18 '21 at 19:34
0

You should probably look at the modules feature of recent Jackson versions.

One possible mechanism would be to use a BeanDeserializerModifier.

I've been looking for a useful online tutorial or example, but nothing immediately appears. It might be possible to work something up if more is known of your context. Are you managing your ObjectMappers manually, or using them in a JAX-RS setting, injected in Spring, or what?

ptomli
  • 11,730
  • 4
  • 40
  • 68