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
;
}
}