Reputation: 6637
I have a simple wrapper class.
class Wrapper {
int id;
Object command;
}
command
could be an object that I get from the outside, and I cannot create an interface to hold the possible types together.
I'd like to serialize it simply:
String json = objectMapper.writeValueAsString(wrapper);
So that I get:
{"id":"1","command":{"type" : "objectType", "key0": "val0", ... other properties...}}
Ideally I'd build a registry with the possible values of type
and the corresponding class names as values, so I could deserialize it like this:
Wrapper wrapper = objectMapper.readValue(bytes, Wrapper.class);
(objectMapper
is com.fasterxml.jackson.databind.ObjectMapper
)
Is there a way to achieve this with Jackson
?
Upvotes: 1
Views: 270
Reputation: 10853
You can use the Jackson polymorphic type handling. You can declare which type the command property can be using @JsonTypeXXX
annotations.
Here is a complete example:
public class JacksonTypeInfoOnObject {
public static class Bean {
@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type")
@JsonSubTypes({
@JsonSubTypes.Type(Command1.class),
@JsonSubTypes.Type(Command2.class)
})
public final Object command;
@JsonCreator
public Bean(@JsonProperty("command") final Object command) {this.command = command;}
@Override
public String toString() {
return "Bean{" +
"command=" + command +
'}';
}
}
@JsonTypeName("cmd1")
public static class Command1 {
@Override
public String toString() {
return "Command1{}";
}
}
@JsonTypeName("cmd2")
public static class Command2 {
@Override
public String toString() {
return "Command2{}";
}
}
public static void main(String[] args) throws IOException {
final ObjectMapper mapper = new ObjectMapper();
mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS);
final List<Bean> list = Arrays.asList(
new Bean(new Command1()),
new Bean(new Command2()));
final String json = mapper.writeValueAsString(list);
System.out.println(json);
final List<Bean> values = mapper.readValue(json, new TypeReference<List<Bean>>() {});
System.out.println(values);
}
}
Output:
[{"command":{"type":"cmd1"}},{"command":{"type":"cmd2"}}]
[Bean{command=Command1{}}, Bean{command=Command2{}}]
Upvotes: 1
Reputation: 48640
I changed the type of your command
property to a Map<String, Object>
and the Wrapper
object can be serialized/deserialized as expected.
Below, is the output generated by the Main
class:
SERIALIZE: {"id":1,"command":{"key0":"val0","type":"objectType"}}
DESERIALIZE: Wrapper [id=1, command={key0=val0, type=objectType}]
package json;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
public class Main {
static ObjectMapper objectMapper = new ObjectMapper();
private static Wrapper createWrapper() {
Wrapper wrapper = new Wrapper();
Map<String, Object> command = new HashMap<String, Object>();
command.put("type", "objectType");
command.put("key0", "val0");
wrapper.id = 1;
wrapper.command = command;
return wrapper;
}
private static String serializeWrapper(Wrapper wrapperObj) {
try {
return objectMapper.writeValueAsString(wrapperObj);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
return null;
}
private static Wrapper deserializeWrapper(String wrapperJsonStr) {
try {
return objectMapper.readValue(wrapperJsonStr, Wrapper.class);
} catch (JsonParseException e) {
e.printStackTrace();
} catch (JsonMappingException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return null;
}
public static void main(String[] args) {
Wrapper wrapper = createWrapper();
String wrapperJsonStr = serializeWrapper(wrapper);
System.out.printf("SERIALIZE: %s%n", wrapperJsonStr);
Wrapper wrapperObj = deserializeWrapper(wrapperJsonStr);
System.out.printf("DESERIALIZE: %s%n", wrapperObj);
}
}
package json;
import java.util.Map;
public class Wrapper {
public int id;
public Map<String, Object> command;
@Override
public String toString() {
return "Wrapper [id=" + id + ", command=" + command + "]";
}
}
Upvotes: 0