Skip to content

JsonFormat.Shape.OBJECT ignored when class implements Map.Entry #865

@DaveGrahamCA

Description

@DaveGrahamCA

The change #565 has overridden the default behavior that is defined by annotations when using JsonFormat.Shape.OBJECT. This is problematic if the Map.Entry is only one aspect of the object. Below is example code that exposes this defect. It represents an attempt to implement the pre Jackson-2.5 behavior for a Map.Entry by forcing the jackson to deal with object as a POJO. But instead of reading the annotations as if it were a POJO it appears to serialize as by using some default Map.Entry algorithm. The behavior is not as expected after annotating the class. This code use to work with Jackson 2.4.

Example files
...
package example;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public class VariableSubstitutionEntry implements Map.Entry<String, List<String>> {

    private static final String JSON_VALUE_FIELD = "value";
    private static final String JSON_KEY_FIELD = "key";
    private final SubstitutionList value = new SubstitutionList();
    private String name;

    public VariableSubstitutionEntry() {
        super();
    }

    public VariableSubstitutionEntry(String variableName, String... valueArray) {
        super();
        add(valueArray);
        name = variableName;
    }

    @JsonIgnore
    @Override
    public SubstitutionList getValue() {
        return value;
    }

    @JsonProperty(JSON_VALUE_FIELD)
    public SubstitutionList getSerializationValue() {
        return value;
    }

    @JsonIgnore
    @Override
    public List<String> setValue(List<String> value) {
        getValue().clear();
        getValue().addAll(value);
        return getValue();
    }

    @JsonIgnore
    public final void add(String... valueArray) {
        value.addAll(Arrays.asList(valueArray));
    }

    @JsonIgnore
    boolean isEmpty() {
        return value.isEmpty();
    }

    @Override
    public String toString() {
        return value.toString();
    }

    @Override
    public int hashCode() {
        return value.hashCode();
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final VariableSubstitutionEntry other = (VariableSubstitutionEntry) obj;
        if (getValue() != other.getValue() && (getValue() == null || !getValue().equals(other.getValue()))) {
            return false;
        }
        return true;
    }

    /**
     * Get the name of the variable to substitute.
     *
     * @return the name of the variable to substitute
     */
    @JsonIgnore
    @Override
    public String getKey() {
        return name;
    }

    /**
     * Set the name of the variable to substitute.
     *
     * @param name the name of the variable to substitute
     */
    @JsonIgnore
    public void setKey(String name) {
        this.name = name;
    }

    /**
     * Get the name of the variable to substitute.
     *
     * @return the name of the variable to substitute
     */
    @JsonProperty(JSON_KEY_FIELD)
    public String getSerializationName() {
        return name;
    }

    /**
     * Set the name of the variable to substitute.
     *
     * @param name the name of the variable to substitute
     */
    @JsonProperty(JSON_KEY_FIELD)
    public void setSerializationName(String name) {
        this.name = name;
    }
}

package example;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * Implementation of
 * <code>List</code> containing variable substitution values.
 */
@JsonDeserialize(contentAs = String.class)
public class SubstitutionList extends ArrayList<String> {

    private static final long serialVersionUID = 1L;

    /**
     * Construct a new instance of
     * <code>SubstitutionList</code>.
     */
    public SubstitutionList() {
        super();
    }

    /**
     * Construct a new instance of
     * <code>SubstitutionList</code> from the given strings.
     *
     * @param strings one or more strings to add to the list
     */
    public SubstitutionList(String... strings) {
        super(Arrays.asList(strings));
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public int hashCode() {
        return toString().hashCode();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder("[\"");
        boolean first = true;
        for (String s : this) {
            if (first) {
                first = false;
            } else {
                sb.append("\",\"");
            }
            sb.append(s);
        }
        sb.append("\"]");
        return sb.toString();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean equals(Object obj) {
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        final SubstitutionList other = (SubstitutionList) obj;
        return toString().equals(other.toString());
    }
}

...

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions