Skip to content

JacksonSampleCustomViewProcessing

markwoon edited this page Feb 27, 2013 · 2 revisions

Custom quoting of JSON String characters

(contributed by Andrei Voden)

Original problem

(copied verbatim from the mailing list)

"Hi. Instead of using class-type filtering I would like to do instance-based one. For example I have classes:

class A {
 String name;
 B  info;
 A child;
}
class B {
 int distance;
 String id;
}

A root = new A();

Now, I would like to serialize instance root in a following way: serialize all fields that belong to the root but for root.child serialize only name. So result would be:

  "root": {
     "name": "somthing",
     "info": { "distance":100, "id":"123"},
     "child": {"name": "lalala"}
   }

... Any ideas whats the easiest way to pass filtering object along during serialization? Filtering object will probably Map object. "

Sample code

And here is eventual code written to achieve custom configurable property filtering for serialization:

public class CustomSerializationView
{
   static class ViewBean
   {
       public String name;
       public String value;
       public String secret;
       public  ViewBean  sibling;
       public  ViewBeanChild   child;

       public ViewBean(String name, String value, String secret) {
           this.name = name;
           this.value = value;
           this.secret = secret;
         child = new ViewBeanChild();
       }
   }
   static class ViewBeanChild
   {
       public  long  id = 123;
       public String name = "child";
       public String address = "123 Street";
   }

   static class FilteredWriter
       extends BeanPropertyWriter
   {
       public FilteredWriter(BeanPropertyWriter w) {
           super(w);
       }

       public void serializeAsField(Object bean, JsonGenerator jgen, SerializerProvider prov)
           throws Exception
       {
         BzStdSerializerProvider myprov = (BzStdSerializerProvider)prov;
         HashMap filter = myprov.getCurrentFilter();
         if (filter == null) {
           super.serializeAsField(bean, jgen, prov);
         } else if (filter.containsKey(this._name)) {
           Object subfilter = filter.get(this._name);
           myprov.pushFilter(HashMap.class.isAssignableFrom(subfilter.getClass()) ? (HashMap)subfilter : null);
           super.serializeAsField(bean, jgen, prov);
           myprov.popFilter();
         }
       }
   }

   public static class CustomBeanFactory
       extends CustomSerializerFactory
               // (CSF extends BeanSerializerFactory)
   {
       @Override
       protected BeanSerializer processViews(SerializationConfig config, BasicBeanDescription beanDesc,
                                             BeanSerializer ser, List<BeanPropertyWriter> props)
       {
           ser = super.processViews(config, beanDesc, ser, props);

           BeanPropertyWriter[] writers = props.toArray(new BeanPropertyWriter[props.size()]);
           for (int i = 0; i < writers.length; ++i) {
             writers[i] = new FilteredWriter (writers[i]);
           }
           ser = ser.withFiltered(writers);

           return ser;
       }
   }
   static  class BzStdSerializerProvider extends StdSerializerProvider {
     private HashMap         _filter;
     private Vector<HashMap> _stack = new Vector();

     public BzStdSerializerProvider() {
       super();
     }
     public BzStdSerializerProvider(HashMap filter) {
       super();
       _filter = filter;
     }
     protected BzStdSerializerProvider(SerializationConfig config, StdSerializerProvider src, SerializerFactory f) {
       super (config, src, f);
     }
     protected BzStdSerializerProvider(SerializationConfig config, StdSerializerProvider src, SerializerFactory f, HashMap filter) {
       super (config, src, f);
       _filter = filter;
     }

     protected StdSerializerProvider createInstance(SerializationConfig config, SerializerFactory jsf)
     {
         return new BzStdSerializerProvider (config, this, jsf, _filter);
     }

     public  HashMap getCurrentFilter () {
       if (_stack.isEmpty())   return _filter;
       return _stack.lastElement();
     }
     public  void pushFilter (HashMap filter) {
       _stack.add(filter);
     }
     public  void popFilter () {
       if (!_stack.isEmpty()) {
         _stack.removeElement(_stack.lastElement());
       }
     }
   }
   public static void main(String[] args) throws Exception
   {
     // create dummy objects
     ViewBean bean = new ViewBean("mr bean", "goofy", "secret!");
     bean.sibling = new ViewBean("sibling", "lala", "boooo");

     // create filtering Map
     String  filter = "{\"name\":0,\"value\":0, \"sibling\":{\"name\":0}, \"child\":{\"id\":0,\"address\":0}}";
     ObjectMapper filterMapper = new ObjectMapper();
     HashMap filterMap = filterMapper.readValue(filter, HashMap.class);

     // custom mapper
     ObjectMapper mapper = new ObjectMapper(null, new BzStdSerializerProvider(filterMap), null);
     mapper.setSerializerFactory(new CustomBeanFactory());

     // First, without enabling view handling:
     System.out.println("With default serializer:"+mapper.writeValueAsString(bean));

     String json = mapper.viewWriter(String.class).writeValueAsString(bean);
     System.out.println("With custom serializer: "+json);
}

CategoryJackson