java 如何覆盖jackson ObjectReader?
java how to override jackson ObjectReader?
我正在使用 jersey 和 jackson 编写休息服务。我有类似 this example
import com.mkyong.Track;
@Path("/json/metallica")
public class JSONService {
@GET
@Path("/get")
@Produces(MediaType.APPLICATION_JSON)
public Track getTrackInJSON() {
Track track = new Track();
track.setTitle("Enter Sandman");
track.setSinger("Metallica");
return track;
}
@POST
@Path("/post")
@Consumes(MediaType.APPLICATION_JSON)
public MyResponse createTrackInJSON(Track track) {
return new MyResponse().setResult(true);
}
}
但在我的例子中,classe Track 不是一个简单的 pojo bean.I 使用 Map 来保存我的数据,我创建了一个方法来从我的对象生成 json和一个解析 json 数据的构造函数。
public class JsonObject {
Map<String, String> data = new HashMap<>();
public String toJson(){
return "";
}
}
public class Track extends JsonObject {
public Track(String json) {
//Parse json
// [...]
}
public Track(JsonNode node) {
//Parse node
// [...]
}
public String getTitle() {
if(data.containsKey("title"))
return data.get("title");
return "";
}
public void setTitle(String title) {
data.put("title", title);
}
public String getSinger() {
if(data.containsKey("singer"))
return data.get("singer");
return "";
}
public void setSinger(String singer) {
data.put("singer", singer);
}
@Override
public String toString() {
return "Track [title=" + getTitle() + ", singer=" + getSinger() + "]";
}
public String toJson() {
return "{\"title\": \"" + getTitle() + "\", \"singer\": \"" + getSinger() + "\"}";
}
}
public class MyResponse extends JsonObject {
public boolean getResult() {
if(data.containsKey("result"))
return (boolean) data.get("result");
return false;
}
public MyResponse setResult(boolean value) {
data.put("result", value);
return this;
}
@Override
public String toString() {
return "{\"result\": " + getResult() + "}";
}
}
所以我的问题是:是否可以在方法调用之前和之后创建操作来告诉杰克逊如何生成或解析我的对象?使用注释 and/or 创建 ObjectReader 或类似的东西?
谢谢
编辑:
谢谢 peeskillet。
我不确定@JsonAnyGetter 和@JsonAnySetter 是我的解决方案。我有许多扩展 JsonObject 的对象,我想将它与 getter 和 setter 一起保存以供我休息 api。
所以我创建了一个通用的 JsonSerializer:
public class MyObjectSerializer extends JsonSerializer<JsonObject> {
@Override
public void serialize(JsonObject value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeRaw(value.toJson());
}
}
然后我将此注释添加到 MyResponse 对象。
@JsonSerialize(using = MyObjectSerializer.class)
public class MyResponse ...
我希望我不必在每个对象中添加此注释,这是在休息服务期间自动完成的 return 但它工作正常并且没有那么严格。
现在我遇到了反序列化的另一个问题。我想要一个带有参数 JsonNode 的通用反序列化器调用构造函数。但是我怎么知道 class 调用的是什么?
我在@JsonDeserialize 注解中看到一个参数"as"。
@JsonDeserialize(using = MyObjectDeserializer.class, as=Track.class)
但我没有找到如何在 JsonDeserializer 中获取此信息。任何的想法 ?
(也许我可以为这个问题另开一个帖子)
要在 JAX-RS 中配置 Jackson,您可以注册一个 Context-Resolver<ObjectMapper>
, as seen in 。如果需要,您可以创建自定义序列化程序。
对于上面发布的特定用例,使用 @JsonAnyGetter
would work without doing any other crazy stuff. @JsonAnySetter
进行 反序列化 .
一样简单
public class JsonObject {
Map<String, String> data = new HashMap<>();
@JsonAnyGetter
public Map<String, String> getData() {
return data;
}
@JsonAnySetter
public void put(String field, String value) {
data.put(field, value);
}
public String toJson(){
return "";
}
}
Jackson 将序列化映射中的所有数据,就好像它们是 class 或子classes 中的属性一样。所以你不需要在 Track
class.
中添加任何属性
我解决了我的问题。
对于序列化,我为我在 contextResolver 中定义的 JsonObject 创建了一个序列化程序。所有扩展 JsonObject 的 类 都使用此序列化程序进行序列化。
public class MyJsonSerializer extends JsonSerializer<JsonObject> {
@Override
public void serialize(JsonObject value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeRaw(value.toJson());
}
}
@Provider
public class JacksonJsonProvider implements ContextResolver<ObjectMapper> {
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
MAPPER.setSerializationInclusion(Include.NON_NULL);
MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
public JacksonJsonProvider() {
SimpleModule simpleModule = new SimpleModule("SimpleModule", new Version(1,0,0,null, null, null));
simpleModule.addSerializer(JsonObject.class, new MyJsonSerializer());
MAPPER.registerModule(simpleModule);
}
@Override
public ObjectMapper getContext(Class<?> type) {
LOGGER.debug("JacksonProvider.getContext() called with type: "+type);
return MAPPER;
}
}
对于反序列化,我使用注解@JsonCreator() 来指示杰克逊使用什么方法创建对象。
@JsonCreator()
public JsonObject(JsonNode json) {
super(json);
}
我正在使用 jersey 和 jackson 编写休息服务。我有类似 this example
import com.mkyong.Track;
@Path("/json/metallica")
public class JSONService {
@GET
@Path("/get")
@Produces(MediaType.APPLICATION_JSON)
public Track getTrackInJSON() {
Track track = new Track();
track.setTitle("Enter Sandman");
track.setSinger("Metallica");
return track;
}
@POST
@Path("/post")
@Consumes(MediaType.APPLICATION_JSON)
public MyResponse createTrackInJSON(Track track) {
return new MyResponse().setResult(true);
}
}
但在我的例子中,classe Track 不是一个简单的 pojo bean.I 使用 Map 来保存我的数据,我创建了一个方法来从我的对象生成 json和一个解析 json 数据的构造函数。
public class JsonObject {
Map<String, String> data = new HashMap<>();
public String toJson(){
return "";
}
}
public class Track extends JsonObject {
public Track(String json) {
//Parse json
// [...]
}
public Track(JsonNode node) {
//Parse node
// [...]
}
public String getTitle() {
if(data.containsKey("title"))
return data.get("title");
return "";
}
public void setTitle(String title) {
data.put("title", title);
}
public String getSinger() {
if(data.containsKey("singer"))
return data.get("singer");
return "";
}
public void setSinger(String singer) {
data.put("singer", singer);
}
@Override
public String toString() {
return "Track [title=" + getTitle() + ", singer=" + getSinger() + "]";
}
public String toJson() {
return "{\"title\": \"" + getTitle() + "\", \"singer\": \"" + getSinger() + "\"}";
}
}
public class MyResponse extends JsonObject {
public boolean getResult() {
if(data.containsKey("result"))
return (boolean) data.get("result");
return false;
}
public MyResponse setResult(boolean value) {
data.put("result", value);
return this;
}
@Override
public String toString() {
return "{\"result\": " + getResult() + "}";
}
}
所以我的问题是:是否可以在方法调用之前和之后创建操作来告诉杰克逊如何生成或解析我的对象?使用注释 and/or 创建 ObjectReader 或类似的东西?
谢谢
编辑:
谢谢 peeskillet。
我不确定@JsonAnyGetter 和@JsonAnySetter 是我的解决方案。我有许多扩展 JsonObject 的对象,我想将它与 getter 和 setter 一起保存以供我休息 api。
所以我创建了一个通用的 JsonSerializer:
public class MyObjectSerializer extends JsonSerializer<JsonObject> {
@Override
public void serialize(JsonObject value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeRaw(value.toJson());
}
}
然后我将此注释添加到 MyResponse 对象。
@JsonSerialize(using = MyObjectSerializer.class)
public class MyResponse ...
我希望我不必在每个对象中添加此注释,这是在休息服务期间自动完成的 return 但它工作正常并且没有那么严格。
现在我遇到了反序列化的另一个问题。我想要一个带有参数 JsonNode 的通用反序列化器调用构造函数。但是我怎么知道 class 调用的是什么?
我在@JsonDeserialize 注解中看到一个参数"as"。
@JsonDeserialize(using = MyObjectDeserializer.class, as=Track.class)
但我没有找到如何在 JsonDeserializer 中获取此信息。任何的想法 ?
(也许我可以为这个问题另开一个帖子)
要在 JAX-RS 中配置 Jackson,您可以注册一个 Context-Resolver<ObjectMapper>
, as seen in
对于上面发布的特定用例,使用 @JsonAnyGetter
would work without doing any other crazy stuff. @JsonAnySetter
进行 反序列化 .
public class JsonObject {
Map<String, String> data = new HashMap<>();
@JsonAnyGetter
public Map<String, String> getData() {
return data;
}
@JsonAnySetter
public void put(String field, String value) {
data.put(field, value);
}
public String toJson(){
return "";
}
}
Jackson 将序列化映射中的所有数据,就好像它们是 class 或子classes 中的属性一样。所以你不需要在 Track
class.
我解决了我的问题。
对于序列化,我为我在 contextResolver 中定义的 JsonObject 创建了一个序列化程序。所有扩展 JsonObject 的 类 都使用此序列化程序进行序列化。
public class MyJsonSerializer extends JsonSerializer<JsonObject> {
@Override
public void serialize(JsonObject value, JsonGenerator gen, SerializerProvider serializers)
throws IOException, JsonProcessingException {
gen.writeRaw(value.toJson());
}
}
@Provider
public class JacksonJsonProvider implements ContextResolver<ObjectMapper> {
private static final ObjectMapper MAPPER = new ObjectMapper();
static {
MAPPER.setSerializationInclusion(Include.NON_NULL);
MAPPER.enable(SerializationFeature.INDENT_OUTPUT);
MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
}
public JacksonJsonProvider() {
SimpleModule simpleModule = new SimpleModule("SimpleModule", new Version(1,0,0,null, null, null));
simpleModule.addSerializer(JsonObject.class, new MyJsonSerializer());
MAPPER.registerModule(simpleModule);
}
@Override
public ObjectMapper getContext(Class<?> type) {
LOGGER.debug("JacksonProvider.getContext() called with type: "+type);
return MAPPER;
}
}
对于反序列化,我使用注解@JsonCreator() 来指示杰克逊使用什么方法创建对象。
@JsonCreator()
public JsonObject(JsonNode json) {
super(json);
}