Apologies in advance. This seems like a simple task, but hours later on Google and with guess/check, I still can’t figure it out.
I’m writing a Java convenience wrapper library for an API my company provides. One of the classes looks something like this:
class View extends Model<View>
{
List<Column> columns;
Column primaryColumn;
}
However, our API actually wants a primaryColumnId integer, not an actual Column object. I want to maintain the strongly-typed getPrimaryColumn() and setPrimaryColumn(Column) in the library to reduce developer error, but I’m having significant difficulty writing some sort of translation between the getter/setter that we need to ser/deser to/from JSON.
I’m using the standard Bean serialization strategy. I’d like to avoid the wholly-custom approach because in reality View has dozens of fields. Here’s what I’ve figured out so far.
I think (haven’t tested yet) that I can handle the serialization case simply by creating a custom JsonSerializer that looks something like:
public static class ColumnIdSerializer extends JsonSerializer<Column>
{
@Override
public void serialize(Column column, JsonGenerator jsonGenerator,
SerializerProvider serializerProvider) throws IOException {
jsonGenerator.writeFieldName("primaryColumnId");
jsonGenerator.writeNumber(column.id);
}
}
And then assigning the annotation to the appropriate place:
@JsonSerialize(using = Column.ColumnIdSerializer.class)
public Column getPrimaryColumn() { /* ... */ }
This allows me to serialize the id rather than the whole class, and rename the key from primaryColumn to primaryColumnId.
Now, we get to deserialization. Here I run into three problems.
The first is that in order to successfully deserialize the column from the id, we have to first have the list of columns. This is solvable using @JsonPropertyOrder on the class. Great, that’s done.
The second is that I need to tell Jackson to look under primaryColumnId rather than primaryColumn for the value. I don’t know how to do this; the JsonDeserializer appears to kick in after the key has already been found, so it’s too late to modify it. JsonSchema looks like it might be relevant but I can’t find any documentation or internet chatter on how to use it.
The third is that from the custom JsonDeserializer class I’ll have to be able to reference the View that’s being deserialized in order to ask it for a Column in return for my id int. There doesn’t appear to be a way to do that.
Should I just cave and add a public getPrimaryColumnId() and setPrimaryColumnId(Integer), or is there a way to overcome these obstacles?
Turns out that since Jackson does nasty reflection, it can see through
privatemethods. So, the trick ended up simply being along the lines of: