Subversion Repositories bacoAlunos

Rev

Blame | Compare with Previous | Last modification | View Log | RSS feed

package genson;

import com.owlike.genson.reflect.BeanDescriptorProvider.CompositeBeanDescriptorProvider;
import com.owlike.genson.reflect.AbstractBeanDescriptorProvider.ContextualFactoryDecorator;
import com.owlike.genson.reflect.AbstractBeanDescriptorProvider.ContextualConverterFactory;

import java.lang.reflect.Type;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Use the GensonBuilder class when you want to create a custom Genson instance. This class allows you
 * for example to register custom converters/serializers/deserializers
 * {@link #withConverters(genson.Converter...)} or custom converter Factories
 * {@link #withConverterFactory(genson.Factory)}.
 * <p/>
 * This class combines the GensonBuilder design pattern with template pattern providing handy
 * configuration and extensibility. All its public methods are intended to be used in the
 * GensonBuilder "style" and its protected methods are part of the template. When you call
 * {@link #create()} method, it will start assembling all the configuration and build all the
 * required components by using the protected methods. For example if you wish to use in your
 * projects a GensonBuilder that will always create some custom
 * {@link genson.reflect.BeanDescriptorProvider BeanDescriptorProvider} you have to
 * extend {@link #createBeanDescriptorProvider()}, or imagine that you implemented some
 * Converters that you always want to register then override {@link #getDefaultConverters()}.
 *
 * @author eugen
 */

public class GensonBuilder {
  private final Map<Type, genson.Serializer<?>> serializersMap = new HashMap<Type, genson.Serializer<?>>();
  private final Map<Type, genson.Deserializer<?>> deserializersMap = new HashMap<Type, genson.Deserializer<?>>();
  private final List<genson.Factory<?>> converterFactories = new ArrayList<genson.Factory<?>>();
  private final List<genson.convert.ContextualFactory<?>> contextualFactories = new ArrayList<genson.convert.ContextualFactory<?>>();
  private final List<genson.reflect.BeanPropertyFactory> beanPropertyFactories = new ArrayList<genson.reflect.BeanPropertyFactory>();

  private boolean skipNull = false;
  private boolean htmlSafe = false;
  private boolean withClassMetadata = false;
  private boolean throwExcOnNoDebugInfo = false;
  private boolean useGettersAndSetters = true;
  private boolean useFields = true;
  private boolean withBeanViewConverter = false;
  private boolean useRuntimeTypeForSerialization = false;
  private boolean withDebugInfoPropertyNameResolver = false;
  private boolean strictDoubleParse = false;
  private boolean indent = false;
  private boolean metadata = false;
  private boolean failOnMissingProperty = false;

  private List<genson.ext.GensonBundle> _bundles = new ArrayList<genson.ext.GensonBundle>();

  private genson.reflect.PropertyNameResolver propertyNameResolver;
  private genson.reflect.BeanMutatorAccessorResolver mutatorAccessorResolver;
  private genson.reflect.VisibilityFilter propertyFilter = genson.reflect.VisibilityFilter.PACKAGE_PUBLIC;
  private genson.reflect.VisibilityFilter methodFilter = genson.reflect.VisibilityFilter.PACKAGE_PUBLIC;
  private genson.reflect.VisibilityFilter constructorFilter = genson.reflect.VisibilityFilter.PACKAGE_PUBLIC;

  private 1.5.0/docs/api/java/lang/ClassLoader.html">ClassLoader classLoader = getClass().getClassLoader();
  private genson.reflect.BeanDescriptorProvider beanDescriptorProvider;
  private 1.5.0/docs/api/java/text/DateFormat.html">DateFormat dateFormat = 1.5.0/docs/api/java/text/SimpleDateFormat.html">SimpleDateFormat.getDateTimeInstance();
  private boolean useDateAsTimestamp = true;
  private boolean classMetadataWithStaticType = true;

  // for the moment we don't allow to override
  private genson.reflect.BeanViewDescriptorProvider beanViewDescriptorProvider;

  private final Map<String, Class<?>> withClassAliases = new HashMap<String, Class<?>>();
  private final Map<Class<?>, BeanView<?>> registeredViews = new HashMap<Class<?>, BeanView<?>>();

  private genson.convert.ChainedFactory customFactoryChain;

  private final Map<Class<?>, Object> defaultValues = new HashMap<Class<?>, Object>();
  private boolean failOnNullPrimitive = false;
  private genson.reflect.RuntimePropertyFilter runtimePropertyFilter = genson.reflect.RuntimePropertyFilter.noFilter;

  public GensonBuilder() {
    defaultValues.put(int.class, 0);
    defaultValues.put(long.class, 0l);
    defaultValues.put(short.class, (short) 0);
    defaultValues.put(double.class, 0d);
    defaultValues.put(float.class, 0f);
    defaultValues.put(boolean.class, false);
    defaultValues.put(byte.class, (byte) 0);
    defaultValues.put(char.class, '\u0000');
  }

  /**
   * Alias used in serialized class metadata instead of the full class name. See
   * {@link genson.convert.ClassMetadataConverter ClassMetadataConverter} for more
   * metadata. If you add an alias, it will automatically enable the class metadata feature,
   * as if you used {@link #useClassMetadata(boolean)}.
   *
   * @param alias
   * @param forClass
   * @return a reference to this builder.
   */

  public GensonBuilder addAlias(1.5.0/docs/api/java/lang/String.html">String alias, Class<?> forClass) {
    withClassMetadata = true;
    withClassAliases.put(alias, forClass);
    return this;
  }

  /**
   * Registers converters mapping them to their corresponding parameterized type.
   *
   * @param converter
   * @return a reference to this builder.
   */

  public GensonBuilder withConverters(genson.Converter<?>... converter) {
    for (genson.Converter<?> c : converter) {
      1.5.0/docs/api/java/lang/reflect/Type.html">Type typeOfConverter = genson.reflect.TypeUtil.typeOf(0,
              genson.reflect.TypeUtil.lookupGenericType(genson.Converter.class, c.getClass()));
      typeOfConverter = genson.reflect.TypeUtil.expandType(typeOfConverter, c.getClass());
      registerConverter(c, typeOfConverter);
    }
    return this;
  }

  /**
   * Register converter by mapping it to type argument.
   *
   * @param converter to register
   * @param type      of objects this converter handles
   * @return a reference to this builder.
   */

  public <T> GensonBuilder withConverter(genson.Converter<T> converter, Class<? extends T> type) {
    registerConverter(converter, type);
    return this;
  }

  /**
   * Register converter by mapping it to the parameterized type of type argument.
   *
   * @param converter to register
   * @param type      of objects this converter handles
   * @return a reference to this builder.
   */

  public <T> GensonBuilder withConverter(genson.Converter<T> converter, GenericType<? extends T> type) {
    registerConverter(converter, type.getType());
    return this;
  }

  private <T> void registerConverter(genson.Converter<T> converter, 1.5.0/docs/api/java/lang/reflect/Type.html">Type type) {
    if (serializersMap.containsKey(type))
      throw new 1.5.0/docs/api/java/lang/IllegalStateException.html">IllegalStateException("Can not register converter "
        + converter.getClass()
        + ". A custom serializer is already registered for type " + type);
    if (deserializersMap.containsKey(type))
      throw new 1.5.0/docs/api/java/lang/IllegalStateException.html">IllegalStateException("Can not register converter "
        + converter.getClass()
        + ". A custom deserializer is already registered for type " + type);
    serializersMap.put(type, converter);
    deserializersMap.put(type, converter);
  }

  public GensonBuilder withSerializers(genson.Serializer<?>... serializer) {
    for (genson.Serializer<?> s : serializer) {
      1.5.0/docs/api/java/lang/reflect/Type.html">Type typeOfConverter = genson.reflect.TypeUtil.typeOf(0,
              genson.reflect.TypeUtil.lookupGenericType(genson.Serializer.class, s.getClass()));
      typeOfConverter = genson.reflect.TypeUtil.expandType(typeOfConverter, s.getClass());
      registerSerializer(s, typeOfConverter);
    }
    return this;
  }

  public <T> GensonBuilder withSerializer(genson.Serializer<T> serializer, Class<? extends T> type) {
    registerSerializer(serializer, type);
    return this;
  }

  public <T> GensonBuilder withSerializer(genson.Serializer<T> serializer, GenericType<? extends T> type) {
    registerSerializer(serializer, type.getType());
    return this;
  }

  private <T> void registerSerializer(genson.Serializer<T> serializer, 1.5.0/docs/api/java/lang/reflect/Type.html">Type type) {
    if (serializersMap.containsKey(type))
      throw new 1.5.0/docs/api/java/lang/IllegalStateException.html">IllegalStateException("Can not register serializer "
        + serializer.getClass()
        + ". A custom serializer is already registered for type " + type);
    serializersMap.put(type, serializer);
  }

  public GensonBuilder withDeserializers(genson.Deserializer<?>... deserializer) {
    for (genson.Deserializer<?> d : deserializer) {
      1.5.0/docs/api/java/lang/reflect/Type.html">Type typeOfConverter = genson.reflect.TypeUtil.typeOf(0,
              genson.reflect.TypeUtil.lookupGenericType(genson.Deserializer.class, d.getClass()));
      typeOfConverter = genson.reflect.TypeUtil.expandType(typeOfConverter, d.getClass());
      registerDeserializer(d, typeOfConverter);
    }
    return this;
  }

  public <T> GensonBuilder withDeserializer(genson.Deserializer<T> deserializer, Class<? extends T> type) {
    registerDeserializer(deserializer, type);
    return this;
  }

  public <T> GensonBuilder withDeserializer(genson.Deserializer<T> deserializer,
                                            GenericType<? extends T> type) {
    registerDeserializer(deserializer, type.getType());
    return this;
  }

  private <T> void registerDeserializer(genson.Deserializer<T> deserializer, 1.5.0/docs/api/java/lang/reflect/Type.html">Type type) {
    if (deserializersMap.containsKey(type))
      throw new 1.5.0/docs/api/java/lang/IllegalStateException.html">IllegalStateException("Can not register deserializer "
        + deserializer.getClass()
        + ". A custom deserializer is already registered for type " + type);
    deserializersMap.put(type, deserializer);
  }

  /**
   * Registers converter factories.
   *
   * @param factory to register
   * @return a reference to this builder.
   */

  public GensonBuilder withConverterFactory(genson.Factory<? extends genson.Converter<?>> factory) {
    converterFactories.add(factory);
    return this;
  }

  /**
   * Registers serializer factories.
   *
   * @param factory to register
   * @return a reference to this builder.
   */

  public GensonBuilder withSerializerFactory(genson.Factory<? extends genson.Serializer<?>> factory) {
    converterFactories.add(factory);
    return this;
  }

  /**
   * Registers deserializer factories.
   *
   * @param factory to register
   * @return a reference to this builder.
   */

  public GensonBuilder withDeserializerFactory(genson.Factory<? extends genson.Deserializer<?>> factory) {
    converterFactories.add(factory);
    return this;
  }

  /**
   * ContextualFactory is actually in a beta status, it will not be removed, but might be
   * refactored.
   */

  public GensonBuilder withContextualFactory(genson.convert.ContextualFactory<?>... factories) {
    contextualFactories.addAll(1.5.0/docs/api/java/util/Arrays.html">Arrays.asList(factories));
    return this;
  }

  /**
   * A ChainedFactory provides a way to use custom Converters that have access to the default Converters.
   * An example of use is to wrap incoming/outgoing json in a root object and delegate then the ser/de to the default
   * Converter.
   *
   * This mechanism is internally used by Genson to decorate the different Converters with additional behaviour
   * (null handling, ser/de of polymorphic types with class info, runtime type based ser/de, etc).
   *
   * Note that you can't use it in situations where you want to start reading/writing some partial infos and want to
   * delegate the rest to the default Converter.
   */

  public GensonBuilder withConverterFactory(genson.convert.ChainedFactory chainedFactory) {
    if (customFactoryChain == null) customFactoryChain = chainedFactory;
    else {
      customFactoryChain.append(chainedFactory);
    }
    return this;
  }

  /**
   * Allows you to register new BeanPropertyFactory responsible of creating BeanProperty
   * accessors, mutators and BeanCreators. This is a very low level feature, you probably
   * don't need it.
   */

  public GensonBuilder withBeanPropertyFactory(genson.reflect.BeanPropertyFactory... factories) {
    beanPropertyFactories.addAll(1.5.0/docs/api/java/util/Arrays.html">Arrays.asList(factories));
    return this;
  }

  /**
   * Register some genson bundles. For example to enable JAXB support:
   * <p/>
   * <pre>
   * builder.withBundle(new JAXBExtension());
   * </pre>
   *
   * <b>All bundles should be registered before any other customization.</b>
   *
   * @see genson.ext.GensonBundle
   */

  public GensonBuilder withBundle(genson.ext.GensonBundle... bundles) {
    for (genson.ext.GensonBundle bundle : bundles) {
      bundle.configure(this);
      _bundles.add(bundle);
    }
    return this;
  }

  /**
   * Override the default classloader
   *
   * @param loader classloader which will be used to load classes while deserializing
   * @return a reference to this builder
   */

  public GensonBuilder withClassLoader(1.5.0/docs/api/java/lang/ClassLoader.html">ClassLoader loader) {
    classLoader = loader;
    return this;
  }


  /**
   * Replaces default {@link genson.reflect.BeanMutatorAccessorResolver
   * BeanMutatorAccessorResolver} by the specified one.
   *
   * @param resolver
   * @return a reference to this builder.
   */

  public GensonBuilder set(genson.reflect.BeanMutatorAccessorResolver resolver) {
    mutatorAccessorResolver = resolver;
    return this;
  }

  /**
   * Replaces default {@link genson.reflect.PropertyNameResolver
   * PropertyNameResolver} by the specified one.
   *
   * @param resolver
   * @return a reference to this builder.
   */

  public GensonBuilder set(genson.reflect.PropertyNameResolver resolver) {
    propertyNameResolver = resolver;
    return this;
  }

  /**
   * Register additional BeanMutatorAccessorResolver that will be used before the standard
   * ones.
   *
   * @param resolvers
   * @return a reference to this builder.
   */

  public GensonBuilder with(genson.reflect.BeanMutatorAccessorResolver... resolvers) {
    if (mutatorAccessorResolver == null)
      mutatorAccessorResolver = createBeanMutatorAccessorResolver();
    if (mutatorAccessorResolver instanceof genson.reflect.BeanMutatorAccessorResolver.CompositeResolver)
      ((genson.reflect.BeanMutatorAccessorResolver.CompositeResolver) mutatorAccessorResolver).add(resolvers);
    else
      throw new 1.5.0/docs/api/java/lang/IllegalStateException.html">IllegalStateException(
        "You can not add multiple resolvers if the base resolver is not of type "
          + genson.reflect.BeanMutatorAccessorResolver.CompositeResolver.class.getName());
    return this;
  }

  public Map<Type, genson.Serializer<?>> getSerializersMap() {
    return 1.5.0/docs/api/java/util/Collections.html">Collections.unmodifiableMap(serializersMap);
  }

  public Map<Type, genson.Deserializer<?>> getDeserializersMap() {
    return 1.5.0/docs/api/java/util/Collections.html">Collections.unmodifiableMap(deserializersMap);
  }

  public 1.5.0/docs/api/java/lang/ClassLoader.html">ClassLoader getClassLoader() {
    return classLoader;
  }

  /**
   * Registers the specified resolvers in the order they were defined and before the standard
   * ones.
   *
   * @param resolvers
   * @return a reference to this builder.
   */

  public GensonBuilder with(genson.reflect.PropertyNameResolver... resolvers) {
    if (propertyNameResolver == null) propertyNameResolver = createPropertyNameResolver();
    if (propertyNameResolver instanceof genson.reflect.PropertyNameResolver.CompositePropertyNameResolver)
      ((genson.reflect.PropertyNameResolver.CompositePropertyNameResolver) propertyNameResolver).add(resolvers);
    else
      throw new 1.5.0/docs/api/java/lang/IllegalStateException.html">IllegalStateException(
        "You can not add multiple resolvers if the base resolver is not of type "
          + genson.reflect.PropertyNameResolver.CompositePropertyNameResolver.class.getName());
    return this;
  }

  /**
   * Renames all fields named field to toName.
   */

  public GensonBuilder rename(1.5.0/docs/api/java/lang/String.html">String field, 1.5.0/docs/api/java/lang/String.html">String toName) {
    return rename(field, null, toName, null);
  }

  /**
   * Renames all fields of type fieldOfType to toName.
   */

  public GensonBuilder rename(Class<?> fieldOfType, 1.5.0/docs/api/java/lang/String.html">String toName) {
    return rename(null, null, toName, fieldOfType);
  }

  /**
   * Renames all fields named field declared in class fromClass to toName.
   */

  public GensonBuilder rename(1.5.0/docs/api/java/lang/String.html">String field, Class<?> fromClass, 1.5.0/docs/api/java/lang/String.html">String toName) {
    return rename(field, fromClass, toName, null);
  }

  /**
   * Renames all fields named field and of type fieldOfType to toName.
   */

  public GensonBuilder rename(1.5.0/docs/api/java/lang/String.html">String field, 1.5.0/docs/api/java/lang/String.html">String toName, Class<?> fieldOfType) {
    return rename(field, null, toName, fieldOfType);
  }

  /**
   * Renames all fields named field, of type fieldOfType and declared in fromClass to toName.
   */

  public GensonBuilder rename(final 1.5.0/docs/api/java/lang/String.html">String field, final Class<?> fromClass, final 1.5.0/docs/api/java/lang/String.html">String toName,
                              final Class<?> ofType) {
    return with(new genson.reflect.RenamingPropertyNameResolver(field, fromClass, ofType, toName));
  }

  public GensonBuilder exclude(1.5.0/docs/api/java/lang/String.html">String field) {
    return filter(field, null, null, true);
  }

  public GensonBuilder exclude(Class<?> fieldOfType) {
    return filter(null, null, fieldOfType, true);
  }

  public GensonBuilder exclude(1.5.0/docs/api/java/lang/String.html">String field, Class<?> fromClass) {
    return filter(field, fromClass, null, true);
  }

  public GensonBuilder exclude(1.5.0/docs/api/java/lang/String.html">String field, Class<?> fromClass, Class<?> ofType) {
    return filter(field, fromClass, ofType, true);
  }

  public GensonBuilder include(1.5.0/docs/api/java/lang/String.html">String field) {
    return filter(field, null, null, false);
  }

  public GensonBuilder include(Class<?> fieldOfType) {
    return filter(null, null, fieldOfType, false);
  }

  public GensonBuilder include(1.5.0/docs/api/java/lang/String.html">String field, Class<?> fromClass) {
    return filter(field, fromClass, null, false);
  }

  public GensonBuilder include(1.5.0/docs/api/java/lang/String.html">String field, Class<?> fromClass, Class<?> ofType) {
    return filter(field, fromClass, ofType, false);
  }

  private GensonBuilder filter(final 1.5.0/docs/api/java/lang/String.html">String field, final Class<?> declaringClass,
                               final Class<?> ofType, final boolean exclude) {
    return with(new genson.reflect.PropertyFilter(exclude, field, declaringClass, ofType));
  }

  /**
   * If true will not serialize null values
   *
   * @param skipNull indicates whether null values should be serialized or not.
   * @return a reference to this builder.
   */

  public GensonBuilder setSkipNull(boolean skipNull) {
    this.skipNull = skipNull;
    return this;
  }

  public boolean isSkipNull() {
    return skipNull;
  }

  /**
   * If true \,<,>,&,= characters will be replaced by \u0027, \u003c, \u003e, \u0026, \u003d
   *
   * @param htmlSafe indicates whether serialized data should be html safe.
   * @return a reference to this builder.
   */

  public GensonBuilder setHtmlSafe(boolean htmlSafe) {
    this.htmlSafe = htmlSafe;
    return this;
  }

  public boolean isHtmlSafe() {
    return htmlSafe;
  }

  /**
   * Indicates whether class metadata should be serialized and used during deserialization.
   *
   * @see genson.convert.ClassMetadataConverter ClassMetadataConverter
   */

  public GensonBuilder useClassMetadata(boolean enabled) {
    this.withClassMetadata = enabled;
    this.metadata = true;
    return this;
  }

  /**
   * Specifies the data format that should be used for java.util.Date serialization and
   * deserialization.
   *
   * @param dateFormat
   * @return a reference to this builder.
   */

  public GensonBuilder useDateFormat(1.5.0/docs/api/java/text/DateFormat.html">DateFormat dateFormat) {
    this.dateFormat = dateFormat;
    return this;
  }

  public boolean isThrowExceptionOnNoDebugInfo() {
    return throwExcOnNoDebugInfo;
  }

  /**
   * Used in conjunction with {@link #useConstructorWithArguments(boolean)}. If true
   * an exception will be thrown when a class has been compiled without debug informations.
   *
   * @param throwExcOnNoDebugInfo
   * @return a reference to this builder.

   * ASMCreatorParameterNameResolver
   */

  public GensonBuilder setThrowExceptionIfNoDebugInfo(boolean throwExcOnNoDebugInfo) {
    this.throwExcOnNoDebugInfo = throwExcOnNoDebugInfo;
    return this;
  }

  /**
   * If true, getters and setters would be used during serialization/deserialization in favor
   * of fields. If there is not getter/setter for a field then the field will be used, except
   * if you specified that fields should not be used with {@link #useFields(boolean)}. By
   * default getters, setters and fields will be used.
   */

  public GensonBuilder useMethods(boolean enabled) {
    this.useGettersAndSetters = enabled;
    return this;
  }

  public GensonBuilder useMethods(boolean enabled, genson.reflect.VisibilityFilter visibility) {
    useMethods(enabled);
    return setMethodFilter(visibility);
  }

  /**
   * If true, fields will be used when no getter/setter is available, except if you specified
   * that no getter/setter should be used with {@link #useMethods(boolean)}, in
   * that case only fields will be used. By default getters, setters and fields will be used.
   */

  public GensonBuilder useFields(boolean enabled) {
    this.useFields = enabled;
    return this;
  }

  public GensonBuilder useFields(boolean enabled, genson.reflect.VisibilityFilter visibility) {
    useFields(enabled);
    return setFieldFilter(visibility);
  }

  /**
   * If true {@link BeanView} mechanism will be enabled.
   */

  public GensonBuilder useBeanViews(boolean enabled) {
    this.withBeanViewConverter = enabled;
    return this;
  }

  /**
   * If true the concrete type of the serialized object will always be used. So if you have
   * List<Number> type it will not use the Number serializer but the one for the concrete type
   * of the current value.
   *
   * @param enabled
   * @return a reference to this builder.
   */

  public GensonBuilder useRuntimeType(boolean enabled) {
    this.useRuntimeTypeForSerialization = enabled;
    return this;
  }

  /**
   * If true constructor and method arguments name will be resolved from the generated debug
   * symbols during compilation. It is a very powerful feature from Genson, you should have a

   * ASMCreatorParameterNameResolver}.
   *
   * @param enabled
   * @return a reference to this builder.
   * @see #setThrowExceptionIfNoDebugInfo(boolean)
   */

  public GensonBuilder useConstructorWithArguments(boolean enabled) {
    this.withDebugInfoPropertyNameResolver = enabled;
    return this;
  }

  public GensonBuilder setFieldFilter(genson.reflect.VisibilityFilter propertyFilter) {
    this.propertyFilter = propertyFilter;
    return this;
  }

  public GensonBuilder setMethodFilter(genson.reflect.VisibilityFilter methodFilter) {
    this.methodFilter = methodFilter;
    return this;
  }

  public GensonBuilder setConstructorFilter(genson.reflect.VisibilityFilter constructorFilter) {
    this.constructorFilter = constructorFilter;
    return this;
  }

  public GensonBuilder useStrictDoubleParse(boolean strictDoubleParse) {
    this.strictDoubleParse = strictDoubleParse;
    return this;
  }

  /**
   * If true outputed json will be indented using two spaces, otherwise (by default) all is
   * printed on same line.
   */

  public GensonBuilder useIndentation(boolean indent) {
    this.indent = indent;
    return this;
  }

  public GensonBuilder useDateAsTimestamp(boolean enabled) {
    this.useDateAsTimestamp = enabled;
    return this;
  }

  public GensonBuilder useMetadata(boolean metadata) {
    this.metadata = metadata;
    return this;
  }

  public GensonBuilder useByteAsInt(boolean enable) {
    if (enable) {
      withConverters(genson.convert.DefaultConverters.ByteArrayAsIntArrayConverter.instance);
    }
    return this;
  }

  /**
   * If set to true, Genson will throw a JsonBindingException when it encounters a property in the incoming json that does not match
   * a property in the class.
   * False by default.
   * @param enable
   * @return
   */

  public GensonBuilder failOnMissingProperty(boolean enable) {
    this.failOnMissingProperty = enable;
    return this;
  }

  /**
   * If set to false, during serialization class metadata will be serialized only for types where the runtime type differs from the static one.
   * Ex:
   *
   * <pre>
   * class Person {
   *   public Address address;
   * }
   * </pre>
   *
   * Here if the concrete instance of address is Address then this type will not be serialized as metadata, but if they differ then
   * it is serialized. By default this option is true, all types are serialized.
   * @param enable
   * @return
   */

  public GensonBuilder useClassMetadataWithStaticType(boolean enable) {
    this.classMetadataWithStaticType = enable;
    return this;
  }

  /**
   * Wrap a single value into a list when a list is expected. Useful when dealing with APIs that unwrap
   * arrays containing a single value. Disabled by default.
   */

  public GensonBuilder acceptSingleValueAsList(boolean enable) {
    if (enable) withConverterFactory(genson.convert.DefaultConverters.SingleValueAsListFactory.instance);
    return this;
  }

  /**
   * Uses the passed value as the default value for this type.
   */

  public GensonBuilder useDefaultValue(5+0%2Fdocs%2Fapi+Object">Object value, Class<?> targetType) {
    defaultValues.put(targetType, value);
    return this;
  }

  /**
   * Will wrap all the root objects under outputKey during serializaiton and unwrap the content under
   * inputKey during deserializaiton. For example:
   *
   * <code>
   *   Genson genson = new GensonBuilder().wrapRootValues("request", "response").create();
   *
   *   // would produce: {"response": {... person properties ...}}
   *   genson.serialize(person);
   *
   *   Person p = genson.deserialize("{\"request\":{...}}", Person.class);
   * </code>
   *
   * If you need this mechanism only for some types or using different root keys, then you can register JaxbBundle with
   * wrapRootValues(true) and annotate the specific classes with XmlRootElement.
   */

  public GensonBuilder wrapRootValues(final 1.5.0/docs/api/java/lang/String.html">String inputKey, final 1.5.0/docs/api/java/lang/String.html">String outputKey) {
    return withConverterFactory(new genson.convert.ChainedFactory() {
      @1.5.0/docs/api/java/lang/Override.html">Override
      protected genson.Converter<?> create(1.5.0/docs/api/java/lang/reflect/Type.html">Type type, genson.Genson genson, genson.Converter<?> nextConverter) {

        return new genson.convert.DefaultConverters.WrappedRootValueConverter<Object>(
            inputKey,
            outputKey,
            (genson.Converter<Object>) nextConverter
        );
      }
    });
  }

  /**
   * False by default. When enabled a JsonBindingException will be thrown if null is encountered during serialization
   * (should never happen) or deserialization for a primitive type.
   */

  public GensonBuilder failOnNullPrimitive(boolean enabled) {
    this.failOnNullPrimitive = enabled;
    return this;
  }

  public GensonBuilder useRuntimePropertyFilter(genson.reflect.RuntimePropertyFilter filter) {
    this.runtimePropertyFilter = filter;
    return this;
  }

  /**
   * Creates an instance of Genson. You may use this method as many times you want. It wont
   * change the state of the builder, in sense that the returned instance will have always the
   * same configuration.
   *
   * @return a new instance of Genson built for the current configuration.
   */

  public genson.Genson create() {
    if (propertyNameResolver == null) propertyNameResolver = createPropertyNameResolver();
    if (mutatorAccessorResolver == null)
      mutatorAccessorResolver = createBeanMutatorAccessorResolver();

    List<genson.Converter<?>> converters = getDefaultConverters();
    addDefaultSerializers(converters);
    addDefaultDeserializers(converters);
    addDefaultSerializers(getDefaultSerializers());
    addDefaultDeserializers(getDefaultDeserializers());

    List<genson.Factory<? extends genson.Converter<?>>> convFactories = new ArrayList<genson.Factory<? extends genson.Converter<?>>>();
    addDefaultConverterFactories(convFactories);
    converterFactories.addAll(convFactories);

    List<genson.Factory<? extends genson.Serializer<?>>> serializerFactories = new ArrayList<genson.Factory<? extends genson.Serializer<?>>>();
    addDefaultSerializerFactories(serializerFactories);
    converterFactories.addAll(serializerFactories);

    List<genson.Factory<? extends genson.Deserializer<?>>> deserializerFactories = new ArrayList<genson.Factory<? extends genson.Deserializer<?>>>();
    addDefaultDeserializerFactories(deserializerFactories);
    converterFactories.addAll(deserializerFactories);

    List<genson.convert.ContextualFactory<?>> defaultContextualFactories = new ArrayList<genson.convert.ContextualFactory<?>>();
    addDefaultContextualFactories(defaultContextualFactories);
    contextualFactories.addAll(defaultContextualFactories);

    beanDescriptorProvider = createBeanDescriptorProvider();

    if (withBeanViewConverter) {
      List<genson.reflect.BeanMutatorAccessorResolver> resolvers = new ArrayList<genson.reflect.BeanMutatorAccessorResolver>();
      resolvers.add(new genson.reflect.BeanViewDescriptorProvider.BeanViewMutatorAccessorResolver());
      resolvers.add(mutatorAccessorResolver);
      beanViewDescriptorProvider = new genson.reflect.BeanViewDescriptorProvider(
        new ContextualConverterFactory(contextualFactories), registeredViews,
        createBeanPropertyFactory(),
        new genson.reflect.BeanMutatorAccessorResolver.CompositeResolver(resolvers), getPropertyNameResolver()
      );
    }

    return create(createConverterFactory(), withClassAliases);
  }

  private void addDefaultSerializers(List<? extends genson.Serializer<?>> serializers) {
    if (serializers != null) {
      for (genson.Serializer<?> serializer : serializers) {
        1.5.0/docs/api/java/lang/reflect/Type.html">Type typeOfConverter = genson.reflect.TypeUtil.typeOf(0,
                genson.reflect.TypeUtil.lookupGenericType(genson.Serializer.class, serializer.getClass()));
        typeOfConverter = genson.reflect.TypeUtil.expandType(typeOfConverter, serializer.getClass());
        if (!serializersMap.containsKey(typeOfConverter))
          serializersMap.put(typeOfConverter, serializer);
      }
    }
  }

  private void addDefaultDeserializers(List<? extends genson.Deserializer<?>> deserializers) {
    if (deserializers != null) {
      for (genson.Deserializer<?> deserializer : deserializers) {
        1.5.0/docs/api/java/lang/reflect/Type.html">Type typeOfConverter = genson.reflect.TypeUtil.typeOf(0, genson.reflect.TypeUtil.lookupGenericType(genson.Deserializer.class, deserializer.getClass()));
        typeOfConverter = genson.reflect.TypeUtil.expandType(typeOfConverter, deserializer.getClass());
        if (!deserializersMap.containsKey(typeOfConverter))
          deserializersMap.put(typeOfConverter, deserializer);
      }
    }
  }

  /**
   * In theory this allows you to extend Genson class and to instantiate it, but actually you
   * can not do it as Genson class is final. If some uses cases are discovered it may change.
   *
   * @param converterFactory
   * @param classAliases
   * @return a new Genson instance.
   */

  protected genson.Genson create(genson.Factory<genson.Converter<?>> converterFactory,
                          Map<String, Class<?>> classAliases) {
    return new genson.Genson(converterFactory, getBeanDescriptorProvider(),
      isSkipNull(), isHtmlSafe(), classAliases, withClassMetadata,
      strictDoubleParse, indent, metadata, failOnMissingProperty, defaultValues, runtimePropertyFilter);
  }

  /**
   * You should override this method if you want to add custom
   * {@link genson.convert.ChainedFactory ChainedFactory} or if you need to chain
   * them differently.
   *
   * @return the converter <u>factory instance that will be used to resolve
   * <strong>ALL</strong> converters</u>.
   */

  protected genson.Factory<genson.Converter<?>> createConverterFactory() {
    genson.convert.ChainedFactory chainHead = new genson.convert.CircularClassReferenceConverterFactory();

    chainHead.append(new genson.convert.NullConverterFactory(failOnNullPrimitive));

    if (useRuntimeTypeForSerialization) chainHead.append(new genson.convert.RuntimeTypeConverter.RuntimeTypeConverterFactory());

    chainHead.append(new genson.convert.ClassMetadataConverter.ClassMetadataConverterFactory(classMetadataWithStaticType));

    if (customFactoryChain != null) chainHead.append(customFactoryChain);

    if (withBeanViewConverter) chainHead.append(new genson.convert.BeanViewConverter.BeanViewConverterFactory(
        getBeanViewDescriptorProvider()));

    ContextualFactoryDecorator ctxFactoryDecorator = new ContextualFactoryDecorator(
      new genson.convert.BasicConvertersFactory(getSerializersMap(), getDeserializersMap(),
        getFactories(), getBeanDescriptorProvider()));

    chainHead.append(ctxFactoryDecorator);

    return chainHead;
  }

  protected genson.reflect.BeanMutatorAccessorResolver createBeanMutatorAccessorResolver() {
    List<genson.reflect.BeanMutatorAccessorResolver> resolvers = new ArrayList<genson.reflect.BeanMutatorAccessorResolver>();
    resolvers.add(new genson.reflect.BeanMutatorAccessorResolver.GensonAnnotationsResolver());

    resolvers.add(new genson.reflect.BeanMutatorAccessorResolver.StandardMutaAccessorResolver(propertyFilter,
      methodFilter, constructorFilter));

    return new genson.reflect.BeanMutatorAccessorResolver.CompositeResolver(resolvers);
  }

  /**
   * You can override this method if you want to change the
   * {@link genson.reflect.PropertyNameResolver PropertyNameResolver} that are
   * registered by default. You can also simply replace the default PropertyNameResolver by
   * setting another one with {@link #set(genson.reflect.PropertyNameResolver)}.
   *
   * @return the property name resolver to be used. It should be an instance of
   * {@link genson.reflect.PropertyNameResolver.CompositePropertyNameResolver
   * PropertyNameResolver.CompositePropertyNameResolver}, otherwise you will not be
   * able to add others PropertyNameResolvers using
   * {@link #with(genson.reflect.PropertyNameResolver...)} method.
   */

  protected genson.reflect.PropertyNameResolver createPropertyNameResolver() {
    List<genson.reflect.PropertyNameResolver> resolvers = new ArrayList<genson.reflect.PropertyNameResolver>();
    resolvers.add(new genson.reflect.PropertyNameResolver.AnnotationPropertyNameResolver());
    resolvers.add(new genson.reflect.PropertyNameResolver.ConventionalBeanPropertyNameResolver());


    return new genson.reflect.PropertyNameResolver.CompositePropertyNameResolver(resolvers);
  }

  /**
   * You can override this methods if you want to change the default converters (remove some,
   * change the order, etc).
   *
   * @return the default converters list, must be not null.
   */

  protected List<genson.Converter<?>> getDefaultConverters() {
    List<genson.Converter<?>> converters = new ArrayList<genson.Converter<?>>();
    converters.add(genson.convert.DefaultConverters.StringConverter.instance);
    converters.add(genson.convert.DefaultConverters.NumberConverter.instance);
    converters.add(new genson.convert.DefaultConverters.DateConverter(dateFormat, useDateAsTimestamp));
    converters.add(genson.convert.DefaultConverters.URLConverter.instance);
    converters.add(genson.convert.DefaultConverters.URIConverter.instance);
    converters.add(genson.convert.DefaultConverters.TimestampConverter.instance);
    converters.add(genson.convert.DefaultConverters.BigDecimalConverter.instance);
    converters.add(genson.convert.DefaultConverters.BigIntegerConverter.instance);
    converters.add(genson.convert.DefaultConverters.UUIDConverter.instance);
    converters.add(genson.convert.DefaultConverters.FileConverter.instance);
    return converters;
  }

  /**
   * Override this method if you want to change the default converter factories.
   *
   * @param factories list, is not null.
   */

  protected void addDefaultConverterFactories(List<genson.Factory<? extends genson.Converter<?>>> factories) {
    factories.add(genson.convert.DefaultConverters.ArrayConverterFactory.instance);
    factories.add(genson.convert.DefaultConverters.CollectionConverterFactory.instance);
    factories.add(genson.convert.DefaultConverters.MapConverterFactory.instance);
    factories.add(genson.convert.DefaultConverters.EnumConverterFactory.instance);
    factories.add(genson.convert.DefaultConverters.PrimitiveConverterFactory.instance);
    factories.add(genson.convert.DefaultConverters.UntypedConverterFactory.instance);
    factories.add(new genson.convert.DefaultConverters.CalendarConverterFactory(
      new genson.convert.DefaultConverters.DateConverter(dateFormat, useDateAsTimestamp)
    ));
  }

  protected void addDefaultContextualFactories(List<genson.convert.ContextualFactory<?>> factories) {
    factories.add(new genson.convert.DefaultConverters.DateContextualFactory());
    factories.add(new genson.convert.DefaultConverters.PropertyConverterFactory());
  }

  protected List<genson.Serializer<?>> getDefaultSerializers() {
    return null;
  }

  protected void addDefaultSerializerFactories(
    List<genson.Factory<? extends genson.Serializer<?>>> serializerFactories) {
  }

  protected List<genson.Deserializer<?>> getDefaultDeserializers() {
    return null;
  }

  protected void addDefaultDeserializerFactories(
    List<genson.Factory<? extends genson.Deserializer<?>>> deserializerFactories) {
  }

  /**
   * Creates the standard BeanDescriptorProvider that will be used to provide
   * {@link genson.reflect.BeanDescriptor BeanDescriptor} instances for
   * serialization/deserialization of all types that couldn't be handled by standard and
   * custom converters and converter factories.
   *
   * @return the BeanDescriptorProvider instance.
   */

  protected genson.reflect.BeanDescriptorProvider createBeanDescriptorProvider() {

    ContextualConverterFactory contextualConverterFactory = new ContextualConverterFactory(contextualFactories);
    genson.reflect.BeanPropertyFactory beanPropertyFactory = createBeanPropertyFactory();

    List<genson.reflect.BeanDescriptorProvider> providers = new ArrayList<genson.reflect.BeanDescriptorProvider>();
    for (genson.ext.GensonBundle bundle : _bundles) {
      genson.reflect.BeanDescriptorProvider provider = bundle.createBeanDescriptorProvider(contextualConverterFactory,
        beanPropertyFactory,
        getMutatorAccessorResolver(),
        getPropertyNameResolver(), this);

      if (provider != null) providers.add(provider);
    }

    providers.add(new genson.reflect.BaseBeanDescriptorProvider(
      new ContextualConverterFactory(contextualFactories),
      createBeanPropertyFactory(), getMutatorAccessorResolver(), getPropertyNameResolver(),
      useGettersAndSetters, useFields, true
    ));

    return new CompositeBeanDescriptorProvider(providers);
  }

  protected genson.reflect.BeanPropertyFactory createBeanPropertyFactory() {
    if (withBeanViewConverter)
      beanPropertyFactories.add(new genson.reflect.BeanViewDescriptorProvider.BeanViewPropertyFactory(
        registeredViews));
    beanPropertyFactories.add(new genson.reflect.BeanPropertyFactory.StandardFactory());
    return new genson.reflect.BeanPropertyFactory.CompositeFactory(beanPropertyFactories);
  }

  protected final genson.reflect.PropertyNameResolver getPropertyNameResolver() {
    return propertyNameResolver;
  }

  protected final genson.reflect.BeanMutatorAccessorResolver getMutatorAccessorResolver() {
    return mutatorAccessorResolver;
  }

  protected final genson.reflect.BeanDescriptorProvider getBeanDescriptorProvider() {
    return beanDescriptorProvider;
  }

  protected final genson.reflect.BeanViewDescriptorProvider getBeanViewDescriptorProvider() {
    return beanViewDescriptorProvider;
  }

  public final List<genson.Factory<?>> getFactories() {
    return 1.5.0/docs/api/java/util/Collections.html">Collections.unmodifiableList(converterFactories);
  }

  public final boolean isDateAsTimestamp() {
    return useDateAsTimestamp;
  }
}