org.simpleframework.xml.convert.ConverterScanner Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of simple-xml Show documentation
Show all versions of simple-xml Show documentation
Simple is a high performance XML serialization and configuration framework for Java
/*
* ConverterScanner.java January 2010
*
* Copyright (C) 2010, Niall Gallagher
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
* implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
package org.simpleframework.xml.convert;
import java.lang.annotation.Annotation;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.strategy.Type;
import org.simpleframework.xml.strategy.Value;
/**
* The ConverterScanner
is used to create a converter
* given a method or field representation. Creation of the converter
* is done using the Convert
annotation, which may
* be used to annotate a field, method or class. This describes the
* implementation to use for object serialization. To account for
* polymorphism the type scanned for annotations can be overridden
* from type provided in the Type
object. This ensures
* that if a collection of objects are serialized the correct
* implementation will be used for each type or subtype.
*
* @author Niall Gallagher
*/
class ConverterScanner {
/**
* This is used to instantiate converters given the type.
*/
private final ConverterFactory factory;
/**
* This is used to build a scanner to scan for annotations.
*/
private final ScannerBuilder builder;
/**
* Constructor for the ConverterScanner
object. This
* uses an internal factory to instantiate and cache all of the
* converters created. This will ensure that there is reduced
* overhead for a serialization process using converters.
*/
public ConverterScanner() {
this.factory = new ConverterFactory();
this.builder = new ScannerBuilder();
}
/**
* This method will lookup and instantiate a converter found from
* scanning the field or method type provided. If the type has
* been overridden then the Value
object will provide
* the type to scan. If no annotation is found on the class, field
* or method then this will return null.
*
* @param type this is the type to search for the annotation
* @param value this contains the type if it was overridden
*
* @return a converter scanned from the provided field or method
*/
public Converter getConverter(Type type, Value value) throws Exception {
Class real = getType(type, value);
Convert convert = getConvert(type, real);
if(convert != null) {
return factory.getInstance(convert);
}
return null;
}
/**
* This method will lookup and instantiate a converter found from
* scanning the field or method type provided. If the type has
* been overridden then the object instance will provide the type
* to scan. If no annotation is found on the class, field or
* method then this will return null.
*
* @param type this is the type to search for the annotation
* @param value this contains the type if it was overridden
*
* @return a converter scanned from the provided field or method
*/
public Converter getConverter(Type type, Object value) throws Exception {
Class real = getType(type, value);
Convert convert = getConvert(type, real);
if(convert != null) {
return factory.getInstance(convert);
}
return null;
}
/**
* This method is used to scan the provided Type
for
* an annotation. If the Type
represents a field or
* method then the annotation can be taken directly from that
* field or method. If however the type represents a class then
* the class itself must contain the annotation.
*
* @param type the field or method containing the annotation
* @param real the type that represents the field or method
*
* @return this returns the annotation on the field or method
*/
private Convert getConvert(Type type, Class real) throws Exception {
Convert convert = getConvert(type);
if(convert == null) {
return getConvert(real);
}
return convert;
}
/**
* This method is used to scan the provided Type
for
* an annotation. If the Type
represents a field or
* method then the annotation can be taken directly from that
* field or method. If however the type represents a class then
* the class itself must contain the annotation.
*
* @param type the field or method containing the annotation
*
* @return this returns the annotation on the field or method
*/
private Convert getConvert(Type type) throws Exception {
Convert convert = type.getAnnotation(Convert.class);
if(convert != null) {
Element element = type.getAnnotation(Element.class);
if(element == null) {
throw new ConvertException("Element annotation required for %s", type);
}
}
return convert;
}
/**
* This method is used to scan the provided Type
for
* an annotation. If the Type
represents a field or
* method then the annotation can be taken directly from that
* field or method. If however the type represents a class then
* the class itself must contain the annotation.
*
* @param real the type that represents the field or method
*
* @return this returns the annotation on the field or method
*/
private Convert getConvert(Class real) throws Exception {
Convert convert = getAnnotation(real, Convert.class);
if(convert != null) {
Root root = getAnnotation(real, Root.class);
if(root == null) {
throw new ConvertException("Root annotation required for %s", real);
}
}
return convert;
}
/**
* This is used to acquire the Convert
annotation from
* the class provided. If the type does not contain the annotation
* then this scans all supertypes until either an annotation is
* found or there are no further supertypes.
*
* @param type this is the type to scan for annotations
* @param label this is the annotation type that is to be found
*
* @return this returns the annotation if found otherwise null
*/
private T getAnnotation(Class> type, Class label) {
return builder.build(type).scan(label);
}
/**
* This is used to acquire the class that should be scanned. The
* type is found either on the method or field, or should there
* be a subtype then the class is taken from the provided value.
*
* @param type this is the type representing the field or method
* @param value this contains the type if it was overridden
*
* @return this returns the class that has been scanned
*/
private Class getType(Type type, Value value) {
Class real = type.getType();
if(value != null) {
return value.getType();
}
return real;
}
/**
* This is used to acquire the class that should be scanned. The
* type is found either on the method or field, or should there
* be a subtype then the class is taken from the provided value.
*
* @param type this is the type representing the field or method
* @param value this contains the type if it was overridden
*
* @return this returns the class that has been scanned
*/
private Class getType(Type type, Object value) {
Class real = type.getType();
if(value != null) {
return value.getClass();
}
return real;
}
}