Home > OS >  Can Jackson automatically treat any constructor parameter as a JsonProperty?
Can Jackson automatically treat any constructor parameter as a JsonProperty?

Time:12-09

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.

CodePudding user response:

You should be able to use @ConstructorProperties to give Jackson a hint for the property names. And @JsonIgnore to ignore fields/getters

import java.beans.ConstructorProperties

public class SimpleClass {
    private String name;

    @JsonIgnore
    private String doNotSerialize;

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

    public String getName() {
        return name;
    }

    // ignore derived properties 
    @JsonIgnore
    public int getSum() {
        return 1 1;
    }
}

CodePudding user response:

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.

  • Related