【问题标题】:Jackson - Modify an attribute at runtime without annotationJackson - 在运行时修改属性而无需注释
【发布时间】:2013-09-21 03:43:39
【问题描述】:

假设我有一个豆子:

public class Msg {
  private int code;
  private Object data;

   ... Getter/setters...
}

我使用这种测试代码将其转换为 JSON 或 XML:

public String convert() {
  Msg msg = new Msg();
  msg.setCode( 42 );
  msg.setData( "Are you suggesting coconuts migrate?" );

  ObjectMapper mapper = new ObjectMapper();
  return mapper.writeValueAsString( msg );
}

输出会是这样的:

{"code":42,"data":"Are you suggesting coconuts migrate?"}

现在假设我想用一些动态名称替换“数据”属性:

public String convert(String name) {
  Msg msg = new Msg();
  msg.setCode( 42 );
  msg.setData( "Are you suggesting coconuts migrate?" );

  ObjectMapper mapper = new ObjectMapper();
  // ...DO SOMETHING WITH MAPPER ...
  return mapper.writeValueAsString( msg );
}

如果我调用函数 convert("toto") 我希望得到这个输出:

{"code":42,"toto":"Are you suggesting coconuts migrate?"}

如果我调用函数 convert("groovy") 我希望得到这样的输出:

{"code":42,"groovy":"Are you suggesting coconuts migrate?"}

当然,我可以在创建 JSON 之后进行字符串替换,但如果您有程序化方法的答案,我会接受。

谢谢

【问题讨论】:

  • 用你想要的键将对象转换为Map<String, Object>,然后序列化?
  • 你是对的,它有效,这就是我目前正在做的事情,但我想知道是否有运行时的方式来做到这一点......

标签: java json jackson


【解决方案1】:

您可以使用PropertyNamingStrategy 类来覆盖类属性。查看此类的简单实现:

class ReplaceNamingStrategy extends PropertyNamingStrategy {

    private static final long serialVersionUID = 1L;

    private Map<String, String> replaceMap;

    public ReplaceNamingStrategy(Map<String, String> replaceMap) {
        this.replaceMap = replaceMap;
    }

    @Override
    public String nameForGetterMethod(MapperConfig<?> config, AnnotatedMethod method, String defaultName) {
        if (replaceMap.containsKey(defaultName)) {
            return replaceMap.get(defaultName);
        }

        return super.nameForGetterMethod(config, method, defaultName);
    }
}

示例程序可能如下所示:

import java.io.IOException;
import java.util.Collections;
import java.util.Map;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;

public class JacksonProgram {

    public static void main(String[] args) throws IOException {
        Msg msg = new Msg();
        msg.setCode(42);
        msg.setData("Are you suggesting coconuts migrate?");

        System.out.println(convert(msg, "test"));
        System.out.println(convert(msg, "toto"));
        System.out.println(convert(msg, "groovy"));
    }

    public static String convert(Msg msg, String name) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setPropertyNamingStrategy(new ReplaceNamingStrategy(Collections.singletonMap("data", name)));
        return mapper.writeValueAsString(msg);
    }
}

上面的程序打印:

{"code":42,"test":"Are you suggesting coconuts migrate?"}
{"code":42,"toto":"Are you suggesting coconuts migrate?"}
{"code":42,"groovy":"Are you suggesting coconuts migrate?"}

【讨论】:

  • 感谢,它运行良好,并且仍然可以为进化定制......
【解决方案2】:

一种可能性是使用所谓的“任何吸气剂”:

public class Msg {
  public int code;

  @JsonAnyGetter
  public Map<String,Object> otherFields() {
    Map<String,Object> extra = new HashMap<String,Object>();
    extra.put("data", findDataObject()); // or whatever mechanism you want
    extra.put("name", "Some Name");
    return extra;
  }
}

这样您就可以返回任意一组动态属性。

您还可以使用匹配的“任何 getter”(@JsonAnyGetter) 机制来接受其他属性。

【讨论】:

    猜你喜欢
    • 2011-03-04
    • 1970-01-01
    • 1970-01-01
    • 2011-06-16
    • 1970-01-01
    • 1970-01-01
    • 2016-11-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多