Reputation: 391
My software revolves heavily around rfid devices. All of these devices have have (mostly) the same configuration options such as what power setting the antennas should transmit at. However the APIs supplied with each reader differ in the way the antenna power is set. Configuration of the readers is done on a central server and saved as a json string. I am trying to come up a way to have a common json string to configure the antenna power (for example) without it having to be customised for each API. Here's what I'm trying to achieve.
The json string for setting antenna power would be something like:
{"power":30}
My super class for configuring power:
public abstract class SetPower<T> {
protected int power;
public SetPower(int power) {
this.power = power;
}
public abstract void configure(T rfidReader);
}
Subclass for configuring power from CompanyX's reader:
public class CompanyXSetPower extends SetPower<CompanyXReader> {
@JsonCreator
public CompanyXSetPower(@JsonProperty("power") int power) {
super(power);
}
@Override
public void configure(CompanyXReader reader) {
reader.setPower((byte) power);
}
}
Subclass for configuring power from CompanyY's reader:
public class CompanyYSetPower extends SetPower<CompanyYReader> {
@JsonCreator
public CompanyYSetPower(@JsonProperty("power") int power) {
super(power);
}
@Override
public void configure(CompanyYReader reader) {
reader.setOutputPower(power);
}
}
What's the 'best' way to deserialize generic json into a specific subclass without having to specific class details to the json string. I am ok with including the superclass details to the json string as there needs to be some way of identifying what object type the json data is for.
Upvotes: 0
Views: 3729
Reputation: 10147
What you want is called deserializing JSON into polymorphic types. (see for example this question for a similar problem).
You will need to add an additional type attribute to your JSON content,
so that for example {"type":"x","power":30}
gets deserialized
into an CompanyXSetPower
object,
and {"type":"y","power":30}
gets deserialized
into an CompanyYSetPower
object.
For this to work you need to enhance your abstract base class SetPower
with
@JsonTypeInfo
and @JsonSubTypes
annotations, so that Jackson will
have enough information about the mapping between JSON and your various Java classes.
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME,
include = JsonTypeInfo.As.PROPERTY, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(value = CompanyXSetPower.class, name = "x"),
@JsonSubTypes.Type(value = CompanyYSetPower.class, name = "y")
})
public abstract class SetPower<T> {
protected int power;
public SetPower(int power) {
this.power = power;
}
public abstract void configure(T rfidReader);
}
The deserialization then can be simply done by:
ObjectMapper objectMapper = new ObjectMapper();
SetPower<?> setPower = objectMapper.readValue(url, SetPower.class);
Upvotes: 3