| // no package, i.e. at root of sample/extra |
| |
| import java.io.*; |
| import java.util.*; |
| |
| import org.codehaus.jackson.*; |
| import org.codehaus.jackson.map.*; |
| import org.codehaus.jackson.map.introspect.BasicBeanDescription; |
| import org.codehaus.jackson.map.ser.BeanSerializer; |
| import org.codehaus.jackson.map.ser.BeanPropertyWriter; |
| import org.codehaus.jackson.map.ser.CustomSerializerFactory; |
| |
| /** |
| * Example code to show how to make use of underlying mechanisms |
| * used for implementing standard JsonView implementation, but |
| * without using <code>\@JsonView</code> annotations. |
| *<p> |
| * In this case, we will just want to suppress output of one of |
| * fields, and tranform value of another. Former could be done |
| * using other (annotation-based) suppression methods. |
| *<p> |
| * Note that for the showed use case this is not the simplest |
| * solution -- basic custom JsonSerializer implementation would be -- |
| * it is just to give an idea of kinds of things that can be |
| * done, and one additional mechanism that allows only partially |
| * custom handling. This is useful for more complex POJOs, where |
| * most of default handling is acceptable. |
| * |
| * @since 1.4 |
| */ |
| public class CustomSerializationView |
| { |
| /* |
| *********************************************************** |
| * First helper classes we need |
| *********************************************************** |
| */ |
| |
| /** |
| * Simple value class handling of which we want to customize. |
| */ |
| static class ViewBean |
| { |
| public String name; |
| public String value; |
| public String secret; |
| |
| public ViewBean(String name, String value, String secret) { |
| this.name = name; |
| this.value = value; |
| this.secret = secret; |
| } |
| } |
| |
| /** |
| * And then custom bean property writer that implements |
| * custom serialization functionality for one of properties |
| */ |
| static class UpperCasingWriter |
| extends BeanPropertyWriter |
| { |
| final BeanPropertyWriter _writer; |
| |
| /** |
| * @param Original unmodified bean property writer that |
| * we delegate some calls to |
| */ |
| public UpperCasingWriter(BeanPropertyWriter w) { |
| // use "copy constructor" to get defaults |
| super(w); |
| _writer = w; |
| } |
| |
| public void serializeAsField(Object bean, JsonGenerator jgen, SerializerProvider prov) |
| throws Exception |
| { |
| // We know the type (although interface can't expose it) |
| String value = ((ViewBean) bean).name; |
| // Convert nulls to "", otherwise upper case |
| value = (value == null) ? "" : value.toUpperCase(); |
| jgen.writeStringField("name", value); |
| } |
| } |
| |
| /** |
| * Custom bean factory that is needed to process bean property writers |
| * to implement custom view handling |
| */ |
| public static class CustomBeanFactory |
| extends CustomSerializerFactory |
| // (CSF extends BeanSerializerFactory) |
| { |
| public CustomBeanFactory() { } |
| |
| /** |
| * Here we will modify serializer such that it has two modes: |
| * default handling when no JsonView is enabled; and other (custom) |
| * when viess are enabled. Note that we could also just have forced |
| * serialization for all cases. |
| */ |
| @Override |
| protected BeanSerializer processViews(SerializationConfig config, BasicBeanDescription beanDesc, |
| BeanSerializer ser, List<BeanPropertyWriter> props) |
| { |
| // Let's use default serializer modification as the baseline |
| ser = super.processViews(config, beanDesc, ser, props); |
| |
| /* And only change handling of that one bean (more likely, |
| * you would want to handle all classes in a package, or with |
| * some name -- this would be less work than having separate |
| * custom serializer for all classes) |
| */ |
| if (beanDesc.classDescribed() == ViewBean.class) { |
| BeanPropertyWriter[] writers = props.toArray(new BeanPropertyWriter[props.size()]); |
| for (int i = 0; i < writers.length; ++i) { |
| String pname = writers[i].getName(); |
| if ("secret".equals(pname)) { |
| // remove serializer, filters it out |
| writers[i] = null; |
| } else if ("name".equals(pname)) { |
| // This one we'll just upper case for fun |
| writers[i] = new UpperCasingWriter(writers[i]); |
| } |
| } |
| // Important: create new serializer with filtered writers! |
| ser = ser.withFiltered(writers); |
| } |
| return ser; |
| } |
| } |
| |
| /* |
| *********************************************************** |
| * Then simple test code |
| *********************************************************** |
| */ |
| |
| public static void main(String[] args) throws Exception |
| { |
| ViewBean bean = new ViewBean("mr bean", "goofy", "secret!"); |
| ObjectMapper mapper = new ObjectMapper(); |
| mapper.setSerializerFactory(new CustomBeanFactory()); |
| |
| // First, without enabling view handling: |
| System.out.println("With default serializer: "+mapper.writeValueAsString(bean)); |
| |
| // Then with customized view-handling |
| StringWriter sw = new StringWriter(); |
| /* note: View class being passed is irrelevant since we customize handling) |
| * Also: setting view would not be necessary if we just completely |
| * overrode handling (we didn't, mostly to show more flexible |
| * approach: conceivably you could have another way for passing |
| * your own view id system, using ThreadLocal or some other |
| * configurable part of <code>SerializationConfig</code> or |
| * <code>SerializerProvider</code>) |
| */ |
| /* note: if we wanted use 'writeValueAsString', would have to call |
| * 'mapper.getSerializationConfig().setSerializationView(...)' first |
| */ |
| mapper.writeValueUsingView(sw, bean, String.class); |
| System.out.println("With custom serializer: "+sw.toString()); |
| } |
| } |