问题
Trying to run the through Jackson library for some upcoming work. I've got the following test model:
Address.java
package com.example.domain;
import java.time.LocalDate;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
public class Address {
private String addressKey;
private String postalCode;
private String country;
@JsonSerialize(using = DateSerializer.class, as = String.class)
@JsonDeserialize(using = DateDeserializer.class, as = LocalDate.class)
private LocalDate dateEntered;
public String getAddressKey() {
return addressKey;
}
public void setAddressKey(String addressKey) {
this.addressKey = addressKey;
}
public String getPostalCode() {
return postalCode;
}
public void setPostalCode(String postalCode) {
this.postalCode = postalCode;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
public LocalDate getDateEntered() {
return dateEntered;
}
public void setDateEntered(LocalDate dateEntered) {
this.dateEntered = dateEntered;
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this, false);
}
@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj, false);
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.SHORT_PREFIX_STYLE, false);
}
}
and a custom serializer for the dateEntered field:
DateSerializer.java
package com.example.domain;
import java.io.IOException;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import org.springframework.boot.jackson.JsonComponent;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
@JsonComponent
public class DateSerializer extends JsonSerializer<LocalDate> {
@Override
public void serialize(LocalDate lc, JsonGenerator jsonGenerator, SerializerProvider serializerProvider)
throws IOException, JsonProcessingException {
String date = lc.format(DateTimeFormatter.ofPattern("dd MM yyyy"));
jsonGenerator.writeString(date);
}
}
I've put together the following test, leveraging the @JsonTest annotation to check if the serializer class is doing what i think it should:
AddressTest.java
@JsonTest
@RunWith(SpringRunner.class)
public class AddressTest {
@Autowired
private JacksonTester<Address> json;
@Test
public void test_Address_serialisation_dateEnteredSerialised() throws Exception {
final Address address = getTestAddress();
assertThat(json.write(address))
.hasJsonPathStringValue("@.dateEntered")
.extractingJsonPathStringValue("@.dateEntered")
.isEqualTo("01 05 2018");
}
private Address getTestAddress() {
final Address testAddress = new Address();
testAddress.setAddressKey("testAddressKey");
testAddress.setCountry("testCountry");
testAddress.setPostalCode("testPostalCode");
testAddress.setDateEntered(LocalDate.of(2018, 5, 1));
return testAddress;
}
}
When i run the serialize test, I get this in console:
com.fasterxml.jackson.databind.JsonMappingException: Invalid definition for property dateEntered (of type 'Lcom/example/domain/Address;'): Can not refine serialization type [simple type, class java.time.LocalDate] into java.lang.String; types not related
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:284)
at com.fasterxml.jackson.databind.SerializerProvider.mappingException(SerializerProvider.java:1110)
at com.fasterxml.jackson.databind.SerializerProvider.reportBadPropertyDefinition(SerializerProvider.java:1180)
at com.fasterxml.jackson.databind.ser.PropertyBuilder.buildWriter(PropertyBuilder.java:101)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._constructWriter(BeanSerializerFactory.java:816)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.findBeanProperties(BeanSerializerFactory.java:610)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.constructBeanSerializer(BeanSerializerFactory.java:399)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.findBeanSerializer(BeanSerializerFactory.java:282)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory._createSerializer2(BeanSerializerFactory.java:234)
at com.fasterxml.jackson.databind.ser.BeanSerializerFactory.createSerializer(BeanSerializerFactory.java:168)
at com.fasterxml.jackson.databind.SerializerProvider._createUntypedSerializer(SerializerProvider.java:1308)
at com.fasterxml.jackson.databind.SerializerProvider._createAndCacheUntypedSerializer(SerializerProvider.java:1279)
at com.fasterxml.jackson.databind.SerializerProvider.findValueSerializer(SerializerProvider.java:536)
at com.fasterxml.jackson.databind.SerializerProvider.findTypedValueSerializer(SerializerProvider.java:743)
at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:330)
at com.fasterxml.jackson.databind.ObjectWriter$Prefetch.serialize(ObjectWriter.java:1427)
at com.fasterxml.jackson.databind.ObjectWriter._configAndWriteValue(ObjectWriter.java:1158)
at com.fasterxml.jackson.databind.ObjectWriter.writeValueAsString(ObjectWriter.java:1031)
at org.springframework.boot.test.json.JacksonTester.writeObject(JacksonTester.java:116)
at org.springframework.boot.test.json.AbstractJsonMarshalTester.write(AbstractJsonMarshalTester.java:133)
at com.example.domain.AddressTest.test_Address_serialisation_dateEnteredSerialised(AddressTest.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:252)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:94)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:191)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
From what I could gather, adding @JsonComponent to the class would allow it to be picked up and registered when used in conjunction with @JsonTest but based on this it doesn't seem like its being scanned and added. Am I missing a step in the test or src code? Its worth noting that the deserialiser is set up the same way(it toStrings the date in a particular format) and it works fine .
回答1:
Specifying as = ...
within @JsonSerialize
is rarely needed, especially when you also specify using = ...
.
Quoted from the javadoc of @JsonSerialize.as:
...
Note: if using is also used it has precedence (since it directly specifies serializer, whereas this would only be used to locate the serializer) and value of this annotation property is ignored.
In your case: Specifying as = String.class
seems to be the culprit
of the not found JSON serializer.
If you omit it and in your Address
class just write
@JsonSerialize(using = DateSerializer.class)
@JsonDeserialize(using = DateDeserializer.class)
private LocalDate dateEntered;
then the DateSerializer
is found and the AddressTest
runs fine without exception.
来源:https://stackoverflow.com/questions/51210284/spring-boot-jacksontester-custom-serializer-not-registered