java - Jackson API: partially update a string -
i have complex json object string:
{ "a": ..., "b":..., /* lots of other properties */ "z":... }
that read partially jackson , map java class:
class partialobjectforb { @jsonproperty("b") private objectb b; }
i use readvalue() method objectmapper class , want... far, good.
now, want update values in partialobjectforb , update initial string had. figured how update java object jackson (by using readerforupdating) can't find how opposite: update json object/string java object.
i know how solve problem using jsonobject. example, if want update 1 value:
jsonobject j = new jsonobject(/* full json string */); j.getjsonobject("b").getjsonobject("bb")/* etc. */.put("bbbb", 4); j.tostring(); // give me full original text "b" updated.
but can't find how jackson.
any idea?
notes:
- my input/output strings, can't change that.
- i don't know data in json object. know may have property "b" , if don't can create it.
- i may want deserialize , update more 1 property @ root level (e.g: "b", "h" , "w").
- this problem not recursive. meaning: have full representation of values unserialize (no unknown properties).
- the json object, string, made of few thousand bytes, piece(s) want update lot smaller (e.g: around 100 bytes).
full executable source benchmark included is:
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) { (int = 0; < 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 manually mapping , figure out in 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; (int = 0; < 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; // make more complex 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 = (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 = 0; try { (final int len = props.length; < 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>> = 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 tricky, since not * have many stack frames spare... 1 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"); // json found on 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\"}}}"; }
Comments
Post a Comment