/**
* Pretend like this class cannot be annotated.
*/
public static final class StringWrapper {
private final String mWrapped;
public StringWrapper(final String s) {
mWrapped = s;
}
@Override
public boolean equals(final Object other) {
if (other instanceof StringWrapper) {
return mWrapped.equals(((StringWrapper) other).mWrapped);
}
return false;
}
public String get() {
return mWrapped;
}
}
/**
* A class in my library.
*/
public static final class SomeClassToSerialize {
@JsonDeserialize(contentConverter = StringWrapperIn.class)
@JsonSerialize(contentConverter = StringWrapperOut.class)
@JsonProperty("field")
private final Optional<StringWrapper> mField;
/**
* For Jackson reading only.
*/
private SomeClassToSerialize() {
mField = null;
}
public SomeClassToSerialize(final Optional<StringWrapper> value) {
mField = value;
}
@Override
public boolean equals(final Object other) {
if (other instanceof SomeClassToSerialize) {
return mField.equals(((SomeClassToSerialize) other).mField);
}
return false;
}
}
public static final class StringWrapperIn extends StdConverter<String, StringWrapper> {
@Override
public StringWrapper convert(final String value) {
System.out.println("Working on the way in");
return new StringWrapper(value);
}
}
public static final class StringWrapperOut extends StdConverter<StringWrapper, String> {
@Override
public String convert(final StringWrapper value) {
System.out.println("Working on the way out");
return value.get();
}
}
public static void main(final String[] args) throws JsonProcessingException {
final SomeClassToSerialize original =
new SomeClassToSerialize(Optional.of(new StringWrapper("value")));
final ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new Jdk8Module());
final String out =
mapper.writer()
.with(INDENT_OUTPUT)
.writeValueAsString(original);
System.out.println(out);
final SomeClassToSerialize in =
mapper.readValue(out, SomeClassToSerialize.class);
assert original.equals(in);
}
The output is
Exception in thread "main" com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class StringWrapper and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS)
...
A slight tweak to instead specify a content serializer fixes it:
public static final class SomeClassToSerialize {
@JsonDeserialize(contentUsing = StringWrapperDeserializer.class)
@JsonSerialize(contentUsing = StringWrapperSerializer.class)
@JsonProperty("field")
private final Optional<StringWrapper> mField;
...
}
public static final class StringWrapperDeserializer extends StdDelegatingDeserializer<StringWrapper> {
public StringWrapperDeserializer() {
super(new StringWrapperIn());
}
/*
* Somewhat unrelated, I don't follow why this override is necessary, since it does exactly what the superclass
* does - except for throwing for any subclass.
*/
@Override
protected StdDelegatingDeserializer<StringWrapper> withDelegate(
final Converter<Object, StringWrapper> converter,
final JavaType delegateType,
final JsonDeserializer<?> delegateDeserializer) {
return new StdDelegatingDeserializer<>(converter, delegateType, delegateDeserializer);
}
}
public static final class StringWrapperSerializer extends StdDelegatingSerializer {
public StringWrapperSerializer() {
super(new StringWrapperOut());
}
}
The output is then
Working on the way out
{
"field" : "value"
}
Working on the way in
This is not a difficult workaround, so it's no problem - just unexpected.
I was surprised to find that
contentConverter
does not work withOptional
, butcontentUsing
does. I think this is effectively the same as https://github.com/FasterXML/jackson-modules-java8/issues/97.The output is
A slight tweak to instead specify a content serializer fixes it:
The output is then
This is not a difficult workaround, so it's no problem - just unexpected.