问题
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