Jesse Barnum
Jesse Barnum

Reputation: 6826

Can Jackson automatically treat any constructor parameter as a JsonProperty?

How do I get Jackson to treat 'name' as if it had a @JsonProperty annotation?

public class SimpleClass {
    private String name;
    private String doNotSerialize;

    public SimpleClass( @JsonProperty("name") String name ) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    
    public int getSum() {
        return 1+1;
    }
}

The way it is now, I get an error, Unrecognized field "sum", because it treats every getter as a serializable property.

If I add a class annotation:

@JsonAutoDetect( getterVisibility = JsonAutoDetect.Visibility.NONE )

I get an empty string when serializing. I was hoping that Jackson would see the @JsonProperty on the constructor parameter and figure it out.

If I change the class annotation to:

@JsonAutoDetect( getterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.ANY )

Then I get the 'doNotSerialize' field included.

If I set a @JsonCreator on the constructor, and change my autodetect, I still get a blank string:

@JsonAutoDetect( getterVisibility = JsonAutoDetect.Visibility.NONE, fieldVisibility = JsonAutoDetect.Visibility.NONE, creatorVisibility = JsonAutoDetect.Visibility.ANY )
public class SimpleClass {
    private String name;
    private String doNotSerialize;

    @JsonCreator
    public SimpleClass( @JsonProperty("name") String name ) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
    
    public int getSum() {
        return 1+1;
    }
}

What I'm hoping is that somehow I can tell Jackson to treat all the constructor parameters as serializable fields, and all other fields / setters as non-serializable.

Upvotes: 0

Views: 896

Answers (2)

lance-java
lance-java

Reputation: 27994

If you want "sum" to be included in the serializad json but want to ignore it when deserializing you can do:

@JsonIgnoreProperties(ignoreUnknown=true)
public class SimpleClass { 
   // properties/getters 

   public int getSum() { return 1+1; }
}

If you want to remove "sum" entirely from the json you can do

@JsonIgnoreProperties({"sum"})
public class SimpleClass { 
   // properties/getters 

   public int getSum() { return 1+1;  }
}

or

public class SimpleClass { 
   // properties/getters 

   @JsonIgnore
   public int getSum() { return 1+1;  }
}

Upvotes: 0

tgdavies
tgdavies

Reputation: 11431

You can use a filter to only serialise getters which have a matching field, e.g.

package org.example;

import com.fasterxml.jackson.annotation.JsonFilter;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
import com.fasterxml.jackson.databind.ser.PropertyWriter;
import com.fasterxml.jackson.databind.ser.impl.SimpleBeanPropertyFilter;
import com.fasterxml.jackson.databind.ser.impl.SimpleFilterProvider;

import java.io.IOException;
import java.io.StringWriter;


public class App {
    @JsonFilter("test")
    public static class SimpleClass {
        private String name;
        private String doNotSerialize;

        public SimpleClass(String name ) {
            this.name = name;
        }

        public String getName() {
            return name;
        }

        public int getSum() {
            return 1+1;
        }
    }
    public static void main( String[] args ) throws IOException {
        SimpleFilterProvider filterProvider = new SimpleFilterProvider();
        filterProvider.addFilter("test", new SimpleBeanPropertyFilter() {
            @Override
            protected boolean include(BeanPropertyWriter writer) {
                return super.include(writer);
            }

            @Override
            protected boolean include(PropertyWriter writer) {
                String name = writer.getName();
                Class clazz = writer.getMember().getDeclaringClass();
                try {
                    clazz.getDeclaredField(name);
                    return super.include(writer);
                } catch (NoSuchFieldException e) {
                    // ignore
                    return false;
                }
            }
        });
        ObjectMapper mapper = new ObjectMapper();
        mapper.setFilterProvider(filterProvider);
        StringWriter sw = new StringWriter();
        mapper.createGenerator(sw).writeObject(new SimpleClass("foo"));
        System.out.println(sw.toString());
    }
}

I don't know your full requirements, but this should be a start.

I haven't tried to do what you actually, asked, that is, look at constructor parameters, but that should be possible too.

Upvotes: 1

Related Questions