【问题标题】:Jackson API: partially update a stringJackson API:部分更新字符串
【发布时间】:2013-07-31 19:26:56
【问题描述】:

我有一个非常复杂的 Json 对象,我得到一个字符串:

{ "a": ..., "b":..., /* lots of other properties */ "z":... }

我与 Jackson 一起阅读部分内容并映射到 Java 类:

class PartialObjectForB { @JsonProperty("b") private ObjectB b; }

我使用 ObjectMapper 类中的 readValue() 方法并得到我想要的……到目前为止,一切都很好。

现在,我想更新 PartialObjectForB 中的一些值并更新我拥有的初始字符串。 我想出了如何使用 jackson 更新 Java 对象(通过使用 readerForUpdating),但找不到相反的方法:使用 Java 对象更新 Json 对象/字符串。

我知道如何使用 JSONObject 快速解决这个问题。例如,如果我只想更新 1 个值:

JSONObject j = new JSONObject(/* the full json string */);
j.getJSONObject("b").getJSONObject("bb")/* etc. */.put("bbbb", 4);
j.toString(); // will give me the full original text with only "b" updated.

但找不到杰克逊的方法。

有什么想法吗?

注意事项:

  • 我的输入/输出是字符串,无法更改。
  • 我不知道json对象中有什么数据。我只知道我可能拥有属性“b”,如果没有,我可以创建它。
  • 我可能想要反序列化和更新多个根级别的属性(例如:“b”、“h”和“w”)。
  • 这个问题不是递归的。含义:我有我反序列化的值的完整表示(没有未知属性)。
  • json 对象作为一个字符串,由几千个字节组成,但我要更新的部分通常要小得多(例如:大约 100 个字节)。

【问题讨论】:

    标签: java json serialization jackson deserialization


    【解决方案1】:

    我能想象到的最简单的解决方案 - 将您的 JSON 反序列化为 Map 类(例如 LinkedHashMap)。请看我下面的例子:

    import java.util.LinkedHashMap;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    public class JacksonProgram {
    
        public static void main(String[] args) throws Exception {
            ObjectMapper mapper = new ObjectMapper();
    
            String json = "{\"a\":\"java.lang.Integer\",\"b\":\"time json\",\"c\":\"action json\",\"d\":[1,2,3]}";
            System.out.println(json);
    
            LinkedHashMap<String, Object> map = mapper.readValue(json, LinkedHashMap.class);
            map.put("b", "Override property or create new");
    
            System.out.println(mapper.writeValueAsString(map));
        }
    }
    

    上面的程序打印:

    {"a":"java.lang.Integer","b":"time json","c":"action json","d":[1,2,3]}
    {"a":"java.lang.Integer","b":"Override property or create new","c":"action json","d":[1,2,3]}
    

    如果你想改变路径的内部属性,你可以这样实现:

    import java.io.IOException;
    import java.util.Arrays;
    import java.util.Collection;
    import java.util.LinkedHashMap;
    import java.util.LinkedList;
    
    import com.fasterxml.jackson.databind.ObjectMapper;
    
    public class JacksonProgram {
    
        public static void main(String[] args) throws IOException {
            ObjectMapper mapper = new ObjectMapper();
    
            String json = "{\"b\":{\"bb\":{\"bbb\":20}}}";
            System.out.println(json);
    
            LinkedHashMap<String, Object> map = mapper.readValue(json, LinkedHashMap.class);
            JsonUpdater updater = new JsonUpdater(map);
            updater.update(Arrays.asList("b", "bb", "bbb"), 4);
    
            System.out.println(mapper.writeValueAsString(map));
        }
    }
    
    class JsonUpdater {
    
        private LinkedHashMap<String, Object> jsonMap;
    
        public JsonUpdater(LinkedHashMap<String, Object> jsonMap) {
            this.jsonMap = jsonMap;
        }
    
        public boolean update(Collection<String> propertiesOnThePath, Object newValue) {
            LinkedList<String> path = new LinkedList<String>(propertiesOnThePath);
            String lastProperty = path.removeLast();
    
            LinkedHashMap<String, Object> objectMap = jsonMap;
            while (!path.isEmpty()) {
                String property = path.poll();
                if (!objectMap.containsKey(property)) {
                    return false;
                }
    
                objectMap = (LinkedHashMap<String, Object>) objectMap.get(property);
            }
    
            if (!objectMap.containsKey(lastProperty)) {
                return false;
            }
    
            objectMap.put(lastProperty, newValue);
    
            return false;
        }
    }
    

    上面的程序打印:

    {"b":{"bb":{"bbb":20}}}
    {"b":{"bb":{"bbb":4}}}
    

    如我们所见:值已更改。但是这个解决方案有很大的缺点——我们必须反序列化所有的 JSON。几千字节的字符串对于 Java 来说不是问题,但如果你真的想优化你的程序,你可以使用ObjectNode 类和ObjectMapper#readTree 方法。请看下面的源代码:

    import com.fasterxml.jackson.databind.ObjectMapper;
    import com.fasterxml.jackson.databind.node.ObjectNode;
    
    public class JacksonProgram {
    
        public static void main(String[] args) throws Exception {
            ObjectMapper mapper = new ObjectMapper();
    
            String json = "{\"a\":\"java.lang.Integer\",\"b\":\"time json\",\"c\":\"action json\",\"d\":[1,2,3]}";
            System.out.println(json);
    
            ObjectNode jsonTree = (ObjectNode) mapper.readTree(json);
            jsonTree.put("b", "Override property or create new");
            System.out.println(jsonTree.toString());
        }
    }
    

    上面的程序打印:

    {"a":"java.lang.Integer","b":"time json","c":"action json","d":[1,2,3]}
    {"a":"java.lang.Integer","b":"Override property or create new","c":"action json","d":[1,2,3]}
    

    我没有进行任何比较测试,但您可以测试哪种解​​决方案更适合您。

    【讨论】:

    • 也许我不明白你的问题。我以为您想更改传入的 JSON 并返回更改后的版本。让我知道如何改进我的答案。
    • 您的回答给了我一些想法……但这并不是我所需要的。事实上,我的 JsonObject 示例隐藏的是我想更新一个对象而不仅仅是 1 个值。如果我重用你的符号,我希望能够做到: jsonTree.put("b", instanceOfObjectB);其中 ObjectB 是一个 Java 对象,杰克逊会自动反序列化其 @JsonProperty 注释......(putPojo 没有帮助)经过多次尝试,......我想我有一个涉及自定义模块和 bean 序列化程序的解决方案。如果可行,我将发布一个完整的示例。与此同时,如果您/某人想到更简单的方法......
    【解决方案2】:

    胜利! :) 我现在有一个实现,它不是很简单。 包括基准 Jackson 与 JSONObject。

    问题逐条描述:

    首先,我在数据存储中有一个大的 json 字符串,我想对其进行部分反序列化和更新。反序列化必须是部分的,但序列化是完整的,所以我不会丢失我没有反序列化的数据。 这是我用于示例的对象:

       private static class KnownPart {
    
            @JsonProperty
            private Customer customer;
            @JsonProperty
            private BrowserInfo browser;
        }
    
        private static class Customer {
    
            @JsonProperty
            private int id;
            @JsonProperty
            private String name;
            @JsonProperty
            private Address[] addresses; // just to make it more complex for this example
    
            public Customer(int id, String name, Address[] addresses) {
                this.id = id;
                this.name = name;
                this.addresses = addresses;
            }
    
            public Customer() {
            }
        }
    
        private static class Address {
    
            @JsonProperty
            private String street;
            @JsonProperty
            private String city;
    
            public Address(String street, String city) {
                this.street = street;
                this.city = city;
            }
    
            public Address() {
            }
        }
    
        private static class BrowserInfo {
    
            @JsonProperty
            private String agent;
            @JsonProperty
            private String version;
    
            public BrowserInfo(String agent, String version) {
                this.agent = agent;
                this.version = version;
            }
    
            public BrowserInfo() {
            }
        }
    

    KnownPart 对象包含超过 2 个属性,但我不知道究竟是哪些属性,我不能保证跟踪哪些属性被添加到 json 字符串...

    我有一个数据存储,它的数据用 Json 编码。当前实现使用 JSONObject 来读取/写入,并支持 jackson 读取 json 并将其映射到“真实”Java 对象(PO​​JO 和更复杂的对象)。 虽然使用 jackson 编写完整的 Json 字符串不是问题,但使用仅代表其一小部分的 Java 对象更新现有字符串要困难得多。

    数据存储问题:

        private static class DataStore {
    
            private final String data;
    
            private DataStore(Customer customer, BrowserInfo browser) throws IOException, JSONException {
                StringWriter sw = new StringWriter(1000);
                try (JsonGenerator jgen = MAPPER.getJsonFactory().createJsonGenerator(sw)) {
                    jgen.writeStartObject();
                    writeBunchOfProperties(jgen);
                    jgen.writeFieldName("customer");
                    jgen.writeRawValue(MAPPER.writeValueAsString(customer));
                    writeBunchOfProperties(jgen);
                    jgen.writeFieldName("browser");
                    jgen.writeRawValue(MAPPER.writeValueAsString(browser));
                    writeBunchOfProperties(jgen);
                    jgen.writeEndObject();
                }
                this.data = sw.toString();
            }
    
            private void writeBunchOfProperties(JsonGenerator jgen) throws IOException {
                int c = new Random().nextInt(3) + 1;
                for (int i = 0; i < c; ++i) {
                    jgen.writeFieldName(RandomStringUtils.random(10));
                    jgen.writeRawValue(JSON_LONG);
                }
            }
    
            public String readData(String query) {
                return data;
            }
    
            private void saveData(String json) {
                // Not implemented
            }
    
            public void saveData(JSONObject json) {
                saveData(json.toString());
            }
    
            public void saveData(Object obj) throws IOException {
                // problem: ?
            }
    
            public <T> T readData(String query, Class<T> clazz) throws IOException {
                return MAPPER.readValue(readData(query), clazz);
            }
    
            public <T> T readDataForUpdating(String query, Class<T> clazz) throws IOException {
                // problem: ?
            }
    

    在更高的层次上,我希望能够执行以下操作:

            public long doSomeWritingWithJackson() throws IOException {
                t0 = System.nanoTime();
                KnownPart obj = store.readDataForUpdating(null, KnownPart.class);
                obj.customer.name = "Jackson Doe";
                obj.browser.version = "10";
                store.saveData(obj);
                t1 = System.nanoTime();
                return t1 - t0;
            }
    

    不会丢失我保存时没有读取的数据。 显然,我不想第二次读取数据,因为我是从远程主机读取的,我不想将它缓存在一些静态/实例映射中,因为我需要它在高并发环境。

    所以解决方案,简而言之就是: - 先读取json字符串的树,用它来将Json对象反序列化为Java对象。 - 存储反序列化对象(在 KnowPart 类中)并将树存储在某个父抽象类中 - 编写一个 Jackson 模块来自定义 bean 的序列化方式。该代码与原始代码几乎相同,不同之处在于,当编写来自 KnownPart 的属性时,它的关键是删除 UnknownPart 对象中的树,然后很容易编写未知部分...

    主要对象变成:

        private static abstract class UnknownPart {
    
             ObjectNode tree;
        }
    
        private static class KnownPart extends UnknownPart {
    
            @JsonProperty
            private Customer customer;
            @JsonProperty
            private BrowserInfo browser;
        }
    

    该模块仅处理 UnknownPart 对象: 私有静态类 MyModule 扩展模块 {

            @Override
            public String getModuleName() {
                return "MyModule";
            }
    
            @Override
            public Version version() {
                return new Version(0, 0, 1, "SNAPSHOT");
            }
    
            @Override
            public void setupModule(Module.SetupContext context) {
                context.addBeanSerializerModifier(new org.codehaus.jackson.map.ser.BeanSerializerModifier() {
                    private UnknownPartSerializer cs;
    
                    @Override
                    public JsonSerializer modifySerializer(SerializationConfig config, BasicBeanDescription beanDesc, JsonSerializer<?> serializer) {
                       return UnknownPart.class.isAssignableFrom(beanDesc.getBeanClass())
                           ? new UnknownPartSerializer((BeanSerializerBase) serializer)
                           : serializer;
                    }
                });
            }
        }
    

    而序列化器是:

        private static class UnknownPartSerializer extends BeanSerializerBase {
    
            public UnknownPartSerializer(BeanSerializerBase src) {
                super(src);
            }
    
            @Override
            public void serialize(Object bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
                UnknownPart up = (UnknownPart) bean;
                jgen.writeStartObject();
                serializeFields(up, jgen, provider);
                jgen.writeEndObject();
            }
    
            protected void serializeFields(UnknownPart bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
                final BeanPropertyWriter[] props;
                if (_filteredProps != null && provider.getSerializationView() != null) {
                    props = _filteredProps;
                } else {
                    props = _props;
                }
                int i = 0;
                try {
                    for (final int len = props.length; i < len; ++i) {
                        BeanPropertyWriter prop = props[i];
                        if (prop != null) { // can have nulls in filtered list
                            prop.serializeAsField(bean, jgen, provider);
                            bean.tree.remove(prop.getName()); // new
                        }
                    }
                    if (_anyGetterWriter != null) {
                        _anyGetterWriter.getAndSerialize(bean, jgen, provider);
                    }
                    // new:
                    Iterator<Entry<String, JsonNode>> it = bean.tree.getFields();
                    while (it.hasNext()) {
                        Entry<String, JsonNode> e = it.next();
                        jgen.writeFieldName(e.getKey());
                        jgen.writeObject(e.getValue());
                    }
                } catch (Exception e) {
                    String name = (i == props.length) ? "[anySetter]"
                            : props[i].getName();
                    wrapAndThrow(provider, e, bean, name);
                } catch (StackOverflowError e) {
                    /* 04-Sep-2009, tatu: Dealing with this is tricky, since we do not
                     *   have many stack frames to spare... just one or two; can't
                     *   make many calls.
                     */
                    JsonMappingException mapE = new JsonMappingException("Infinite recursion (StackOverflowError)", e);
                    String name = (i == props.length) ? "[anySetter]"
                            : props[i].getName();
                    mapE.prependPath(new JsonMappingException.Reference(bean, name));
                    throw mapE;
                }
            }
        }
    

    同时,我写了一个基准来确认(或不确认)这个解决方案比 JSONObject 对于大 Json 字符串更快...... 测试比较: - 使用 JSONObject 读取(无映射) - 与杰克逊一起阅读 - 与杰克逊一起读树 - 用 JSONObject 读/写 - 与杰克逊一起读/写 而且确实更快:)

    在 1000 次迭代之后,不包括潜在的类加载或 JVM 所做的一些初始化,我得到了,在纳秒内:

    -- AVERAGE ----------------------------------------------------------------------------
    |    1|        860,560|        157,772|        234,654|      1,595,018|        488,427|
    ---------------------------------------------------------------------------------------
    |     |  RO JSONObject|     RO Jackson|    R/- Jackson| R/W JSONObject|    R/W Jackson|
    ---------------------------------------------------------------------------------------
    

    【讨论】:

      【解决方案3】:

      包含基准的完整可执行源代码是:

      import java.io.IOException;
      import java.io.StringWriter;
      import java.util.Iterator;
      import java.util.Map.Entry;
      import java.util.Random;
      import org.apache.commons.lang3.RandomStringUtils;
      import org.apache.commons.lang3.StringUtils;
      import org.codehaus.jackson.JsonGenerationException;
      import org.codehaus.jackson.JsonGenerator;
      import org.codehaus.jackson.JsonNode;
      import org.codehaus.jackson.Version;
      import org.codehaus.jackson.annotate.JsonProperty;
      import org.codehaus.jackson.map.DeserializationConfig;
      import org.codehaus.jackson.map.JsonMappingException;
      import org.codehaus.jackson.map.JsonSerializer;
      import org.codehaus.jackson.map.Module;
      import org.codehaus.jackson.map.ObjectMapper;
      import org.codehaus.jackson.map.SerializationConfig;
      import org.codehaus.jackson.map.SerializerProvider;
      import org.codehaus.jackson.map.introspect.BasicBeanDescription;
      import org.codehaus.jackson.map.ser.BeanPropertyWriter;
      import org.codehaus.jackson.map.ser.std.BeanSerializerBase;
      import org.codehaus.jackson.node.ObjectNode;
      import org.json.JSONException;
      import org.json.JSONObject;
      
      public class JacksonModule {
      
          private static final ObjectMapper MAPPER = new ObjectMapper();
          private static final int COUNT = 0;
          private static final int REPEAT_HEADER = 40;
      
          static {
              MAPPER.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
              MAPPER.configure(SerializationConfig.Feature.WRITE_NULL_PROPERTIES, false);
              MAPPER.registerModule(new MyModule());
          }
          private DataProcessor sdp;
          private long[] sum = new long[5];
      
          public static void main(String[] args) throws IOException, JSONException {
              new JacksonModule().start();
          }
      
          public JacksonModule() throws IOException, JSONException {
              this.sdp = new DataProcessor();
          }
      
          public void start() throws IOException, JSONException {
              run(-1, false); // load classes: slow
              if (COUNT > 0) {
                  for (int i = 0; i < COUNT; ++i) {
                      if (i % REPEAT_HEADER == 0) {
                          System.out.println("---------------------------------------------------------------------------------------");
                          print("", "RO JSONObject", "RO Jackson", "R/- Jackson", "R/W JSONObject", "R/W Jackson");
                          System.out.println("---------------------------------------------------------------------------------------");
                      }
                      run(i, true);
                  }
                  System.out.println("-- AVERAGE ----------------------------------------------------------------------------");
                  print(1, sum[0] / COUNT, sum[1] / COUNT, sum[2] / COUNT, sum[3] / COUNT, sum[4] / COUNT);
                  System.out.println("---------------------------------------------------------------------------------------");
                  print("", "RO JSONObject", "RO Jackson", "R/- Jackson", "R/W JSONObject", "R/W Jackson");
                  System.out.println("---------------------------------------------------------------------------------------");
              }
          }
      
          public void run(int i, boolean print) throws JSONException, IOException {
              long t1 = sdp.doReadWithJSONObject();
              long t2 = sdp.doReadWithJackson();
              long t3 = sdp.doReadForUpdatingWithJacksonButDontWrite();
              long t4 = sdp.doSomeWritingWithJSONObject();
              long t5 = sdp.doSomeWritingWithJackson();
              if (print) {
                  print(i, t1, t2, t3, t4, t5);
                  sum[0] += t1;
                  sum[1] += t2;
                  sum[2] += t3;
                  sum[3] += t4;
                  sum[4] += t5;
              }
          }
      
          private void print(int index, long t1, long t2, long t3, long t4, long t5) {
              print(Integer.toString(index), String.format("%,d", t1), String.format("%,d", t2), String.format("%,d", t3), String.format("%,d", t4), String.format("%,d", t5));
          }
      
          private void print(String i0, String a, String b, String c, String d, String e) {
              System.out.println("|"
                      + StringUtils.leftPad(i0, 5) + "|"
                      + StringUtils.leftPad(a, 15) + "|"
                      + StringUtils.leftPad(b, 15) + "|"
                      + StringUtils.leftPad(c, 15) + "|"
                      + StringUtils.leftPad(d, 15) + "|"
                      + StringUtils.leftPad(e, 15) + "|");
          }
      
          private static class DataProcessor {
      
              private DataStore store;
              private long t0, t1;
      
              private DataProcessor() throws IOException, JSONException {
                  this.store = new DataStore(customer, browser);
              }
      
              public long doReadWithJSONObject() throws JSONException {
                  t0 = System.nanoTime();
                  JSONObject json = new JSONObject(store.readData(null)); // can throw JSONException
                  JSONObject customer = json.getJSONObject("customer");  // can throw JSONException
                  JSONObject browserInfo = json.getJSONObject("browser");  // can throw JSONException
                  // need to do manually the mapping and figure out what is exactly in this object. Hell no!
                  t1 = System.nanoTime();
                  return t1 - t0;
              }
      
              public long doReadWithJackson() throws IOException {
                  t0 = System.nanoTime();
                  KnownPart obj = store.readData(null, KnownPart.class);
                  t1 = System.nanoTime();
                  return t1 - t0;
              }
      
              public long doReadForUpdatingWithJacksonButDontWrite() throws IOException {
                  t0 = System.nanoTime();
                  KnownPart obj = store.readDataForUpdating(null, KnownPart.class);
                  t1 = System.nanoTime();
                  return t1 - t0;
              }
      
              public long doSomeWritingWithJSONObject() throws JSONException {
                  t0 = System.nanoTime();
                  JSONObject json = new JSONObject(store.readData(null)); // can throw JSONException
                  JSONObject customer = json.getJSONObject("customer");  // can throw JSONException
                  JSONObject browserInfo = json.getJSONObject("browser");  // can throw JSONException
                  customer.put("name", "Jackson Doe");
                  browserInfo.put("version", "10");
                  store.saveData(json);
                  t1 = System.nanoTime();
                  return t1 - t0;
              }
      
              public long doSomeWritingWithJackson() throws IOException {
                  t0 = System.nanoTime();
                  KnownPart obj = store.readDataForUpdating(null, KnownPart.class);
                  obj.customer.name = "Jackson Doe";
                  obj.browser.version = "10";
                  store.saveData(obj);
                  t1 = System.nanoTime();
                  return t1 - t0;
              }
          }
      
          private static class DataStore {
      
              private final String data;
      
              private DataStore(Customer customer, BrowserInfo browser) throws IOException, JSONException {
                  StringWriter sw = new StringWriter(1000);
                  try (JsonGenerator jgen = MAPPER.getJsonFactory().createJsonGenerator(sw)) {
                      jgen.writeStartObject();
                      writeBunchOfProperties(jgen);
                      jgen.writeFieldName("customer");
                      jgen.writeRawValue(MAPPER.writeValueAsString(customer));
                      writeBunchOfProperties(jgen);
                      jgen.writeFieldName("browser");
                      jgen.writeRawValue(MAPPER.writeValueAsString(browser));
                      writeBunchOfProperties(jgen);
                      jgen.writeEndObject();
                  }
                  this.data = sw.toString();
              }
      
              private void writeBunchOfProperties(JsonGenerator jgen) throws IOException {
                  int c = new Random().nextInt(3) + 1;
                  for (int i = 0; i < c; ++i) {
                      jgen.writeFieldName(RandomStringUtils.random(10));
                      jgen.writeRawValue(JSON_LONG);
                  }
              }
      
              public String readData(String query) {
                  return data;
              }
      
              private void saveData(String json) {
                  // TODO
              }
      
              public void saveData(JSONObject json) {
                  saveData(json.toString());
              }
      
              public void saveData(Object obj) throws IOException {
                  saveData(MAPPER.writeValueAsString(obj));
              }
      
              public <T> T readData(String query, Class<T> clazz) throws IOException {
                  return MAPPER.readValue(readData(query), clazz);
              }
      
              public <T extends UnknownPart> T readDataForUpdating(String query, Class<T> clazz) throws IOException {
                  ObjectNode root = (ObjectNode) MAPPER.readTree(readData(query));
                  T obj = MAPPER.readValue(root, clazz);
                  obj.tree = root;
                  return obj;
              }
          }
      
          private static abstract class UnknownPart {
      
               ObjectNode tree;
          }
      
          private static class KnownPart extends UnknownPart {
      
              @JsonProperty
              private Customer customer;
              @JsonProperty
              private BrowserInfo browser;
          }
      
          private static class Customer {
      
              @JsonProperty
              private int id;
              @JsonProperty
              private String name;
              @JsonProperty
              private Address[] addresses; // just to make it more complex for this example
      
              public Customer(int id, String name, Address[] addresses) {
                  this.id = id;
                  this.name = name;
                  this.addresses = addresses;
              }
      
              public Customer() {
              }
          }
      
          private static class Address {
      
              @JsonProperty
              private String street;
              @JsonProperty
              private String city;
      
              public Address(String street, String city) {
                  this.street = street;
                  this.city = city;
              }
      
              public Address() {
              }
          }
      
          private static class BrowserInfo {
      
              @JsonProperty
              private String agent;
              @JsonProperty
              private String version;
      
              public BrowserInfo(String agent, String version) {
                  this.agent = agent;
                  this.version = version;
              }
      
              public BrowserInfo() {
              }
          }
      
          private static class MyModule extends Module {
      
              @Override
              public String getModuleName() {
                  return "MyModule";
              }
      
              @Override
              public Version version() {
                  return new Version(0, 0, 1, "SNAPSHOT");
              }
      
              @Override
              public void setupModule(Module.SetupContext context) {
                  context.addBeanSerializerModifier(new org.codehaus.jackson.map.ser.BeanSerializerModifier() {
                      private UnknownPartSerializer cs;
      
                      @Override
                      public JsonSerializer modifySerializer(SerializationConfig config, BasicBeanDescription beanDesc, JsonSerializer<?> serializer) {
                          return UnknownPart.class.isAssignableFrom(beanDesc.getBeanClass())
                             ? new UnknownPartSerializer((BeanSerializerBase) serializer)
                             : serializer;
                      }
                  });
              }
          }
      
          private static class UnknownPartSerializer extends BeanSerializerBase {
      
              public UnknownPartSerializer(BeanSerializerBase src) {
                  super(src);
              }
      
              @Override
              public void serialize(Object bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
                  UnknownPart up = (UnknownPart) bean;
                  jgen.writeStartObject();
                  serializeFields(up, jgen, provider);
                  jgen.writeEndObject();
              }
      
              protected void serializeFields(UnknownPart bean, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonGenerationException {
                  final BeanPropertyWriter[] props;
                  if (_filteredProps != null && provider.getSerializationView() != null) {
                      props = _filteredProps;
                  } else {
                      props = _props;
                  }
                  int i = 0;
                  try {
                      for (final int len = props.length; i < len; ++i) {
                          BeanPropertyWriter prop = props[i];
                          if (prop != null) { // can have nulls in filtered list
                              prop.serializeAsField(bean, jgen, provider);
                              bean.tree.remove(prop.getName());
                          }
                      }
                      if (_anyGetterWriter != null) {
                          _anyGetterWriter.getAndSerialize(bean, jgen, provider);
                      }
                      Iterator<Entry<String, JsonNode>> it = bean.tree.getFields();
                      while (it.hasNext()) {
                          Entry<String, JsonNode> e = it.next();
                          jgen.writeFieldName(e.getKey());
                          jgen.writeObject(e.getValue());
                      }
                  } catch (Exception e) {
                      String name = (i == props.length) ? "[anySetter]"
                              : props[i].getName();
                      wrapAndThrow(provider, e, bean, name);
                  } catch (StackOverflowError e) {
                      /* 04-Sep-2009, tatu: Dealing with this is tricky, since we do not
                       *   have many stack frames to spare... just one or two; can't
                       *   make many calls.
                       */
                      JsonMappingException mapE = new JsonMappingException("Infinite recursion (StackOverflowError)", e);
                      String name = (i == props.length) ? "[anySetter]"
                              : props[i].getName();
                      mapE.prependPath(new JsonMappingException.Reference(bean, name));
                      throw mapE;
                  }
              }
          }
          private static Customer customer = new Customer(1, "John Doe", new Address[]{
              new Address("broadway av", "new york"),
              new Address("peachtree st", "atlanta")
          });
          private static BrowserInfo browser = new BrowserInfo("IE", "6.0");
          // some json found on the internet
          private static final String JSON_LONG = "{\"web-app\": {"
                  + "\"servlet\": ["
                  + "{"
                  + "\"servlet-name\": \"cofaxCDS\","
                  + "\"servlet-class\": \"org.cofax.cds.CDSServlet\","
                  + "\"init-param\": {"
                  + "\"configGlossary:installationAt\": \"Philadelphia, PA\","
                  + "\"configGlossary:adminEmail\": \"ksm@pobox.com\","
                  + "\"configGlossary:poweredBy\": \"Cofax\","
                  + "\"configGlossary:poweredByIcon\": \"/images/cofax.gif\","
                  + "\"configGlossary:staticPath\": \"/content/static\","
                  + "\"templateProcessorClass\": \"org.cofax.WysiwygTemplate\","
                  + "\"templateLoaderClass\": \"org.cofax.FilesTemplateLoader\","
                  + "\"templatePath\": \"templates\","
                  + "\"templateOverridePath\": \"\","
                  + "\"defaultListTemplate\": \"listTemplate.htm\","
                  + "\"defaultFileTemplate\": \"articleTemplate.htm\","
                  + "\"useJSP\": false,"
                  + "\"jspListTemplate\": \"listTemplate.jsp\","
                  + "\"jspFileTemplate\": \"articleTemplate.jsp\","
                  + "\"cachePackageTagsTrack\": 200,"
                  + "\"cachePackageTagsStore\": 200,"
                  + "\"cachePackageTagsRefresh\": 60,"
                  + "\"cacheTemplatesTrack\": 100,"
                  + "\"cacheTemplatesStore\": 50,"
                  + "\"cacheTemplatesRefresh\": 15,"
                  + "\"cachePagesTrack\": 200,"
                  + "\"cachePagesStore\": 100,"
                  + "\"cachePagesRefresh\": 10,"
                  + "\"cachePagesDirtyRead\": 10,"
                  + "\"searchEngineListTemplate\": \"forSearchEnginesList.htm\","
                  + "\"searchEngineFileTemplate\": \"forSearchEngines.htm\","
                  + "\"searchEngineRobotsDb\": \"WEB-INF/robots.db\","
                  + "\"useDataStore\": true,"
                  + "\"dataStoreClass\": \"org.cofax.SqlDataStore\","
                  + "\"redirectionClass\": \"org.cofax.SqlRedirection\","
                  + "\"dataStoreName\": \"cofax\","
                  + "\"dataStoreDriver\": \"com.microsoft.jdbc.sqlserver.SQLServerDriver\","
                  + "\"dataStoreUrl\": \"jdbc:microsoft:sqlserver://LOCALHOST:1433;DatabaseName=goon\","
                  + "\"dataStoreUser\": \"sa\","
                  + "\"dataStorePassword\": \"dataStoreTestQuery\","
                  + "\"dataStoreTestQuery\": \"SET NOCOUNT ON;select test='test';\","
                  + "\"dataStoreLogFile\": \"/usr/local/tomcat/logs/datastore.log\","
                  + "\"dataStoreInitConns\": 10,"
                  + "\"dataStoreMaxConns\": 100,"
                  + "\"dataStoreConnUsageLimit\": 100,"
                  + "\"dataStoreLogLevel\": \"debug\","
                  + "\"maxUrlLength\": 500}},"
                  + "{"
                  + "\"servlet-name\": \"cofaxEmail\","
                  + "\"servlet-class\": \"org.cofax.cds.EmailServlet\","
                  + "\"init-param\": {"
                  + "\"mailHost\": \"mail1\","
                  + "\"mailHostOverride\": \"mail2\"}},"
                  + "{"
                  + "\"servlet-name\": \"cofaxAdmin\","
                  + "\"servlet-class\": \"org.cofax.cds.AdminServlet\"},"
                  + ""
                  + "{"
                  + "\"servlet-name\": \"fileServlet\","
                  + "\"servlet-class\": \"org.cofax.cds.FileServlet\"},"
                  + "{"
                  + "\"servlet-name\": \"cofaxTools\","
                  + "\"servlet-class\": \"org.cofax.cms.CofaxToolsServlet\","
                  + "\"init-param\": {"
                  + "\"templatePath\": \"toolstemplates/\","
                  + "\"log\": 1,"
                  + "\"logLocation\": \"/usr/local/tomcat/logs/CofaxTools.log\","
                  + "\"logMaxSize\": \"\","
                  + "\"dataLog\": 1,"
                  + "\"dataLogLocation\": \"/usr/local/tomcat/logs/dataLog.log\","
                  + "\"dataLogMaxSize\": \"\","
                  + "\"removePageCache\": \"/content/admin/remove?cache=pages&id=\","
                  + "\"removeTemplateCache\": \"/content/admin/remove?cache=templates&id=\","
                  + "\"fileTransferFolder\": \"/usr/local/tomcat/webapps/content/fileTransferFolder\","
                  + "\"lookInContext\": 1,"
                  + "\"adminGroupID\": 4,"
                  + "\"betaServer\": true}}],"
                  + "\"servlet-mapping\": {"
                  + "\"cofaxCDS\": \"/\","
                  + "\"cofaxEmail\": \"/cofaxutil/aemail/*\","
                  + "\"cofaxAdmin\": \"/admin/*\","
                  + "\"fileServlet\": \"/static/*\","
                  + "\"cofaxTools\": \"/tools/*\"},"
                  + ""
                  + "\"taglib\": {"
                  + "\"taglib-uri\": \"cofax.tld\","
                  + "\"taglib-location\": \"/WEB-INF/tlds/cofax.tld\"}}}";
      }
      

      【讨论】:

        猜你喜欢
        • 2017-12-04
        • 1970-01-01
        • 2010-12-25
        • 2012-07-25
        • 2022-01-01
        • 2013-06-26
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多