Blame |
Last modification |
View Log
| RSS feed
package com.owlike.genson.convert;
import java.lang.reflect.Type;
import com.owlike.genson.Converter;
import com.owlike.genson.Factory;
import com.owlike.genson.Genson;
/**
* A chained factory of Converters that gives the ability to implementations to decorate the
* converter created by the next factory.
* <p/>
* One of Genson big strengths is its extensive use of Decorator and Chain of Responsibility design
* patterns. Chain of responsibility is applied in chaining Factories that can build Decorated
* Converters. ChainedFactory is the base class for such factories. But as ChainedFactory next
* element is an instance of Factory, you are free to apply the chain principle for your custom
* factories differently if you want.
* <p/>
* The global idea behind this design is to provide great extensibility to the library by allowing
* to add new functionalities to existing converters in a non intrusive way (extension and source
* modification). This is achieved by applying the decorator pattern. Here is an example of a
* decorated converter that adds null handling support.
* <p/>
* <pre>
* public class NullConverter extends Wrapper<Converter<Object>> implements
* Converter<Object> {
* private final Converter<Object> converter;
*
* public NullConverter(Converter<Object> converter) {
* super(converter);
* this.converter = converter;
* }
*
* public void serialize(Object obj, ObjectWriter writer, Context ctx) {
* if (obj == null)
* writer.writeNull();
* else
* converter.serialize(obj, writer, ctx);
* }
*
* public Object deserialize(ObjectReader reader, Context ctx) {
* if (TypeValue.NULL == reader.getTypeValue()) {
* return null;
* } else
* return converter.deserialize(reader, ctx);
*
* }
* }
*
* // now we need a factory to create the nullconverter for type T and wire it with the existing
* // factories so we can get an instance of the converter for that type.
* public class NullConverterFactory extends ChainedFactory {
* public NullConverterFactory(Factory<Converter<?>> next) {
* super(next);
* }
*
* public Converter<?> create(Type type, Genson genson, Converter<?> nextConverter) {
* return new NullConverter(nextConverter);
* }
* }
* </pre>
* <p/>
* As you can see it is pretty simple but also powerful. Note that our NullConverter extends
* Wrapper class. When you encapsulate converters you should extend Wrapper
* class this way Genson can access the class information of wrapped converters. Imagine for example
* that you put some annotation on converter A and wrap it in converter B, now if you wrap B in C
* you wont be able to get class information of A (ex: its annotations). Wrapper class
* allows to merge class information of current implementation and the wrapped one.
*
* @author eugen
* @see com.owlike.genson.convert.NullConverter NullConverter
* @see com.owlike.genson.convert.BasicConvertersFactory BasicConvertersFactory
* @see com.owlike.genson.Wrapper Wrapper
*/
public abstract class ChainedFactory
implements Factory
<Converter
<?>> {
private Factory
<? extends Converter
<?>> next
;
protected ChainedFactory
() {
}
protected ChainedFactory
(Factory
<Converter
<?>> next
) {
this.
next = next
;
}
public Converter
<?> create
(1.5.0/docs/api/java/lang/reflect/Type.html">Type type, Genson genson
) {
Converter
<?> nextConverter =
null;
if (next
!=
null) {
nextConverter = next.
create(type, genson
);
}
Converter
<?> converter = create
(type, genson, nextConverter
);
return converter ==
null ? nextConverter : converter
;
}
/**
* This method will be called by {@link #create(Type, Genson)} with nextConverter being the
* converter created for current type by the next factory. This means that ChainedFactory will
* first create a converter with the next factory and then use it's own create method.
*
* @param type for which this factory must provide a converter
* @param genson instance that you can use when you need a converter for some other type (for
* example a converter of List<Integer> will need a converter for Integer type).
* @param nextConverter created by the next factory, may be null.
* @return null or a converter for this type
*/
protected abstract Converter
<?> create
(1.5.0/docs/api/java/lang/reflect/Type.html">Type type, Genson genson, Converter
<?> nextConverter
);
/**
* Chains this factory with next and returns next (the tail) so you can do things like
* chain1.withNext(new chain2).withNext(new chain3); the resulting chain is
* chain1=>chain2=>chain3. Don't forget to keep a reference to the head (chain1).
*
* @param next factory
* @return the next factory passed as argument
*/
public final <T
extends Factory
<? extends Converter
<?>>> T withNext
(T next
) {
if (this.
next !=
null)
throw new 1.5.0/docs/api/java/lang/IllegalStateException.html">IllegalStateException("next factory has already been set for " + getClass
()
+
" you can not override it!");
this.
next = next
;
return next
;
}
public final <T
extends Factory
<? extends Converter
<?>>> T append
(T next
) {
ChainedFactory f =
this;
while(f.
next() !=
null) {
if (!(f.
next() instanceof ChainedFactory
)) {
throw new 1.5.0/docs/api/java/lang/UnsupportedOperationException.html">UnsupportedOperationException("Last element in the chain is not a ChainedFactory");
}
f =
(ChainedFactory
) f.
next();
}
return f.
withNext(next
);
}
/**
* @return a reference to the next factory, may be null.
*/
public final Factory
<? extends Converter
<?>> next
() {
return next
;
}
}