Tushar Patel
Tushar Patel

Reputation: 365

How do I serialize a java bean using jackson and customize map key name?

I need to create a Map from java bean such that the key is prefixed with name of the java bean variable. I am using jackson for this. Example given below:

public class Address{
        String city;
        String state;

        //setters and getters
    }   

Address address = new Address();
address.setCity("myCity");
address.setState("myState");

I am creating map using following:

ObjectMapper objectMapper = new ObjectMapper();
Map map = objectMapper.convertValue(address, HashMap.class);

Which gives me following output:

{"city":"myCity", "state":"myState"}

I need to add class variable name to the key as shown below:

{"address.city":"myCity", "address.state":"myState"}

How do I achieve that?

Upvotes: 0

Views: 1726

Answers (2)

araqnid
araqnid

Reputation: 133482

It is possible to customise bean serialization by registering a BeanSerializerModifier. This specifically supports renaming properties by applying a NameTransformer to each BeanPropertyWriter.

@Test
public void prepend_class_name_to_property_keys() throws Exception {
    ObjectMapper mapper = new ObjectMapper();
    Function<Class<?>, String> classPrefix = clazz -> clazz.getSimpleName().toLowerCase() + ".";
    mapper.registerModule(new Module() {
        @Override
        public String getModuleName() {
            return "Example";
        }

        @Override
        public Version version() {
            return Version.unknownVersion();
        }

        @Override
        public void setupModule(SetupContext context) {
            context.addBeanSerializerModifier(new BeanSerializerModifier() {
                @Override
                public List<BeanPropertyWriter> changeProperties(SerializationConfig config,
                        BeanDescription beanDesc, List<BeanPropertyWriter> beanProperties) {
                    String prefix = classPrefix.apply(beanDesc.getBeanClass());
                    return beanProperties.stream().map(prop -> prop.rename(new NameTransformer() {
                        @Override
                        public String transform(String name) {
                            return prefix + name;
                        }

                        @Override
                        public String reverse(String transformed) {
                            return transformed.substring(prefix.length());
                        }
                    })).collect(toList());
                }
            });
        }
    });
    assertThat(mapper.writeValueAsString(new Address("somewhere", "someplace")),
            equivalentTo("{ 'address.line1' : 'somewhere', 'address.line2' : 'someplace'}"));
}

public static final class Address {
    public final String line1;
    public final String line2;

    public Address(String line1, String line2) {
        this.line1 = line1;
        this.line2 = line2;
    }
}

Upvotes: 0

Erwin
Erwin

Reputation: 3366

If you have jackson-annotations enabled:

public class Address{
    @JsonProperty("address.city")
    String city;
    @JsonProperty("address.state")
    String state;

    //setters and getters
}

read more about it here: https://github.com/FasterXML/jackson-annotations

Upvotes: 2

Related Questions