Use @JsonSerialize(using=MySerializer.class) on a @OneToMany Set<Object>

耗尽温柔 提交于 2019-12-13 16:29:24

问题


In a Spring Boot/Spring Data Rest project i have issues to use a custom JsonSerializer<Set<Object>> on a @OneToMany property. When i do an HTTP GET /collection request i have the following error:

Failed to write HTTP message: org.springframework.http.converter.HttpMessageNotWritableException: Could not write content: Can not override serializer (through reference chain: org.springframework.hateoas.Resources["_embedded"]->java.util.UnmodifiableMap["analogParameters"]->java.util.ArrayList[0]); nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not override serializer (through reference chain: org.springframework.hateoas.Resources["_embedded"]->java.util.UnmodifiableMap["analogParameters"]->java.util.ArrayList[0])

Below is an extract of my entity class:

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="output_parameter_id")
@JsonSerialize(using=InputParametersSerializer.class)
//@Transcient
private Set<InputParameter> inputParameters = new HashSet<InputParameter>();

public Set<InputParameter> getInputParameters() {
    return inputParameters;
}

public void setInputParameters(Set<InputParameter> inputParameters) {
    this.inputParameters = inputParameters;
}

And the JsonSerializer<Set<InputParameter>>

public class InputParametersSerializer 
    extends JsonSerializer<Set<InputParameter>> {

    static final long serialVersionUID = 123L;

    public void serialize (Set<InputParameter> ips, JsonGenerator jg, 
            SerializerProvider sp) 
        throws IOException {

        jg.writeString("Yeah");

    }

}

If i remove @OneToMany and define the property as @transient it works as expected.

InputParameter entity has no Repository associated (it is not exported as a rest resource).

How can a make use of a JsonSerializer on a @OneToMany property?


回答1:


I ran into a very similar issue while using Spring Boot 2.1.0. Adding a custom serializer, both with using and keyUsing, works fine, but a custom deserializer with a @OneToMany annotated field throws out the same JsonMappingException: Can not override serializer message you got, while with an @ElementCollection it just plain gets ignored. I suspect Spring Data Rest does some undocumented magic in order to take care of the (de)serialization of these kinds of fields that does not play nice with the addition of a custom deserializer. My workaround to this was adding an extra JSON field through an annotated getter and setter. With your example, it would look like:

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="output_parameter_id")
private Set<InputParameter> inputParameters = new HashSet<InputParameter>();

public Set<InputParameter> getInputParameters() {
    return inputParameters;
}

public void setInputParameters(Set<InputParameter> inputParameters) {
    this.inputParameters = inputParameters;
}


@JsonSerialize(using=InputParametersSerializer.class)
public Set<InputParameter> getInputParametersSet() {
    return getInputParameters();
}


@JsonDeserialize(using=InputParametersDeserializer.class)
public void setInputParametersSet(Set<InputParameter> inputParameters) {
    setInputParameters(inputParameters);
}

Which will output something like

{
...
  "inputParameters" : ...,
  "inputParametersSet" : ...,
...
}

While not ideal, serialization and deserialization of this field works as expected. alternatively, in order to keep the field name, a similar workaround worked with @ElementCollection but not with @OneToMany:

@OneToMany(cascade=CascadeType.ALL)
@JoinColumn(name="output_parameter_id")
@JsonIgnore
private Set<InputParameter> inputParameters = new HashSet<InputParameter>();

public Set<InputParameter> getInputParameters() {
    return inputParameters;
}

public void setInputParameters(Set<InputParameter> inputParameters) {
    this.inputParameters = inputParameters;
}


@JsonProperty("inputParameters")
@JsonSerialize(using=InputParametersSerializer.class)
public Set<InputParameter> getInputParametersSet() {
    return getInputParameters();
}

@JsonProperty("inputParameters")
@JsonDeserialize(using=InputParametersDeserializer.class)
public void setInputParametersSet(Set<InputParameter> inputParameters) {
    setInputParameters(inputParameters);
}

In the end I had to go with the first approach.



来源:https://stackoverflow.com/questions/40490867/use-jsonserializeusing-myserializer-class-on-a-onetomany-setobject

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!