| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you 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.apache.directmemory.lightning.base; |
| |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Type; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Map.Entry; |
| import java.util.Set; |
| |
| import org.apache.directmemory.lightning.Marshaller; |
| import org.apache.directmemory.lightning.MarshallerContext; |
| import org.apache.directmemory.lightning.TypeBindableMarshaller; |
| import org.apache.directmemory.lightning.bindings.AnnotatedBinder; |
| import org.apache.directmemory.lightning.bindings.AttributeBinder; |
| import org.apache.directmemory.lightning.bindings.ClassBinder; |
| import org.apache.directmemory.lightning.configuration.SerializerDefinition; |
| import org.apache.directmemory.lightning.configuration.TypeIntrospector; |
| import org.apache.directmemory.lightning.exceptions.SerializerDefinitionException; |
| import org.apache.directmemory.lightning.generator.DefinitionBuildingContext; |
| import org.apache.directmemory.lightning.generator.DefinitionVisitor; |
| import org.apache.directmemory.lightning.instantiator.ObjectInstantiatorFactory; |
| import org.apache.directmemory.lightning.internal.InternalMarshallerContext; |
| import org.apache.directmemory.lightning.internal.VisitableMarshallerContext; |
| import org.apache.directmemory.lightning.internal.beans.introspection.AnnotatedTypeIntrospector; |
| import org.apache.directmemory.lightning.internal.util.TypeUtil; |
| import org.apache.directmemory.lightning.metadata.Attribute; |
| import org.apache.directmemory.lightning.metadata.PropertyDescriptor; |
| |
| import com.carrotsearch.hppc.cursors.ObjectObjectCursor; |
| |
| public abstract class AbstractSerializerDefinition |
| implements SerializerDefinition |
| { |
| |
| private final VisitableMarshallerContext marshallerContext = new VisitableMarshallerContext(); |
| |
| private final Set<SerializerDefinition> children = new HashSet<SerializerDefinition>(); |
| |
| private final Map<PropertyDescriptor, Marshaller> propertyMarshallers = |
| new HashMap<PropertyDescriptor, Marshaller>(); |
| |
| private final Map<AnnotatedBinder, AnnotationBinderDefinition<?>> annotationBinders = |
| new HashMap<AnnotatedBinder, AnnotationBinderDefinition<?>>(); |
| |
| private DefinitionBuildingContext definitionBuildingContext; |
| |
| private ObjectInstantiatorFactory objectInstantiatorFactory = null; |
| |
| private Class<? extends Annotation> attributeAnnotation = null; |
| |
| private AbstractSerializerDefinition parent = null; |
| |
| @Override |
| public final void configure( DefinitionBuildingContext definitionBuildingContext, |
| ObjectInstantiatorFactory objectInstantiatorFactory ) |
| { |
| // Save PropertyDescriptorFactory for later use in configure() |
| this.definitionBuildingContext = definitionBuildingContext; |
| |
| // Save ObjectInstantiatorFactory for later use in configure() |
| this.objectInstantiatorFactory = objectInstantiatorFactory; |
| |
| // Read the configuration |
| configure(); |
| } |
| |
| @Override |
| public final void acceptVisitor( DefinitionVisitor visitor ) |
| { |
| // Start visiting |
| visitor.visitSerializerDefinition( this ); |
| |
| // Visit the attribute annotation if set |
| Class<? extends Annotation> attributeAnnotation = findAttributeAnnotation( this ); |
| if ( attributeAnnotation != null ) |
| { |
| visitor.visitAttributeAnnotation( attributeAnnotation ); |
| } |
| |
| // Visit all direct marshallers |
| Iterator<ObjectObjectCursor<Type, Marshaller>> iterator = marshallerContext.getInternalMap().iterator(); |
| while ( iterator.hasNext() ) |
| { |
| ObjectObjectCursor<Type, Marshaller> entry = iterator.next(); |
| visitor.visitClassDefine( entry.key, entry.value ); |
| } |
| |
| // Visit annotated properties |
| Iterator<AnnotationBinderDefinition<?>> annotationIterator = annotationBinders.values().iterator(); |
| while ( annotationIterator.hasNext() ) |
| { |
| AnnotationBinderDefinition<?> annotationBinderDefinition = annotationIterator.next(); |
| annotationBinderDefinition.acceptVisitor( visitor ); |
| } |
| |
| // Visit all property definitions |
| for ( Entry<PropertyDescriptor, Marshaller> entry : propertyMarshallers.entrySet() ) |
| { |
| visitor.visitPropertyDescriptor( entry.getKey(), entry.getValue() ); |
| |
| Class<?> type = entry.getKey().getType(); |
| if ( type.isPrimitive() || type.isArray() && type.getComponentType().isPrimitive() ) |
| { |
| continue; |
| } |
| |
| visitor.visitClassDefine( type, entry.getValue() ); |
| } |
| |
| // Visit all children |
| for ( SerializerDefinition child : children ) |
| { |
| child.configure( definitionBuildingContext, objectInstantiatorFactory ); |
| child.acceptVisitor( visitor ); |
| } |
| |
| // Finalize visit |
| visitor.visitFinalizeSerializerDefinition( this ); |
| } |
| |
| protected abstract void configure(); |
| |
| protected <T> ClassBinder<T> serialize( final Class<T> clazz ) |
| { |
| return buildClassBinder( clazz ); |
| } |
| |
| protected void install( SerializerDefinition childSerializer ) |
| { |
| children.add( childSerializer ); |
| if ( childSerializer instanceof AbstractSerializerDefinition ) |
| { |
| ( (AbstractSerializerDefinition) childSerializer ).parent = this; |
| } |
| } |
| |
| protected void describesAttributes( Class<? extends Annotation> attributeAnnotation ) |
| { |
| this.attributeAnnotation = attributeAnnotation; |
| } |
| |
| protected <V> AttributeBinder<V> attribute( final String attribute ) |
| { |
| return new DefinedAttributeBinder<V>() |
| { |
| |
| @Override |
| protected void setDeclaringClass( Class<?> declaringClass ) |
| { |
| super.setDeclaringClass( declaringClass ); |
| try |
| { |
| Field reflectiveField = declaringClass.getDeclaredField( attribute ); |
| reflectiveField.setAccessible( true ); |
| property = reflectiveField; |
| } |
| catch ( Exception e ) |
| { |
| throw new SerializerDefinitionException( "Property " + property + " could not be found for type " |
| + declaringClass.getCanonicalName(), e ); |
| } |
| } |
| }; |
| } |
| |
| protected <V> AttributeBinder<V> attribute( final Field attribute ) |
| { |
| return new DefinedAttributeBinder<V>() |
| { |
| |
| { |
| property = attribute; |
| declaringClass = attribute.getDeclaringClass(); |
| } |
| }; |
| } |
| |
| private <T> ClassBinder<T> buildClassBinder( final Class<T> clazz ) |
| { |
| return new ClassBinder<T>() |
| { |
| |
| @Override |
| public AnnotatedBinder attributes() |
| { |
| return buildAnnotatedBinder( this, attributeAnnotation ); |
| } |
| |
| @Override |
| public AnnotatedBinder attributes( Class<? extends Annotation> annotation ) |
| { |
| return buildAnnotatedBinder( this, annotation ); |
| } |
| |
| @Override |
| public Class<T> getType() |
| { |
| return clazz; |
| } |
| |
| @Override |
| @SuppressWarnings( "unchecked" ) |
| public void using( Class<?> clazz ) |
| { |
| if ( Marshaller.class.isAssignableFrom( clazz ) ) |
| { |
| try |
| { |
| using( ( (Class<Marshaller>) clazz ).newInstance() ); |
| } |
| catch ( Exception e ) |
| { |
| throw new SerializerDefinitionException( "Marshaller class " + clazz.getCanonicalName() |
| + " could not be instantiated. Is there a standard (public) constructor?", e ); |
| } |
| } |
| |
| } |
| |
| @Override |
| public void using( Marshaller marshaller ) |
| { |
| if ( marshaller instanceof AbstractObjectMarshaller ) |
| { |
| marshallerContext.bindMarshaller( clazz, |
| new ObjenesisDelegatingMarshaller( |
| (AbstractObjectMarshaller) marshaller, |
| objectInstantiatorFactory ) ); |
| } |
| else |
| { |
| marshallerContext.bindMarshaller( clazz, marshaller ); |
| } |
| } |
| |
| @Override |
| public void using( TypeIntrospector typeIntrospector ) |
| { |
| // TODO Auto-generated method stub |
| |
| } |
| |
| @Override |
| public void attributes( AttributeBinder<?>... attributes ) |
| { |
| for ( AttributeBinder<?> attribute : attributes ) |
| { |
| if ( attribute instanceof DefinedAttributeBinder ) |
| { |
| DefinedAttributeBinder<?> binder = (DefinedAttributeBinder<?>) attribute; |
| binder.setDeclaringClass( getType() ); |
| binder.build(); |
| } |
| } |
| } |
| }; |
| } |
| |
| private <T> AnnotatedBinder buildAnnotatedBinder( final ClassBinder<T> classBinder, |
| final Class<? extends Annotation> annotation ) |
| { |
| |
| return new AnnotatedBinder() |
| { |
| |
| private final AnnotationBinderDefinition<T> binder = new AnnotationBinderDefinition<T>( classBinder ); |
| |
| { |
| annotationBinders.put( this, binder ); |
| } |
| |
| @Override |
| public AnnotatedBinder exclude( String property ) |
| { |
| binder.addExclude( property ); |
| return this; |
| } |
| |
| @Override |
| public AnnotatedBinder excludes( String... properties ) |
| { |
| for ( String property : properties ) |
| { |
| binder.addExclude( property ); |
| } |
| return this; |
| } |
| }; |
| } |
| |
| private Class<? extends Annotation> findAttributeAnnotation( AbstractSerializerDefinition abstractSerializerDefinition ) |
| { |
| if ( attributeAnnotation != null ) |
| { |
| return attributeAnnotation; |
| } |
| |
| if ( parent != null ) |
| { |
| return abstractSerializerDefinition.findAttributeAnnotation( parent ); |
| } |
| |
| return Attribute.class; |
| } |
| |
| private class AnnotationBinderDefinition<T> |
| { |
| |
| private final AnnotatedTypeIntrospector typeIntrospector; |
| |
| private final ClassBinder<T> classBinder; |
| |
| private final List<String> excludes = new ArrayList<String>(); |
| |
| private AnnotationBinderDefinition( ClassBinder<T> classBinder ) |
| { |
| this.typeIntrospector = |
| new AnnotatedTypeIntrospector( findAttributeAnnotation( AbstractSerializerDefinition.this ), excludes ); |
| this.classBinder = classBinder; |
| } |
| |
| public void addExclude( String exclude ) |
| { |
| excludes.add( exclude ); |
| } |
| |
| public void acceptVisitor( DefinitionVisitor visitor ) |
| { |
| MarshallerContext marshallers = combineMarshallers( AbstractSerializerDefinition.this ); |
| List<PropertyDescriptor> propertyDescriptors = |
| typeIntrospector.introspect( classBinder.getType(), definitionBuildingContext.getMarshallerStrategy(), |
| marshallers, definitionBuildingContext.getPropertyDescriptorFactory() ); |
| |
| for ( PropertyDescriptor propertyDescriptor : propertyDescriptors ) |
| { |
| Class<?> fieldType = propertyDescriptor.getType(); |
| Marshaller marshaller = propertyDescriptor.getMarshaller(); |
| visitor.visitAnnotatedAttribute( propertyDescriptor, marshaller ); |
| |
| if ( fieldType.isPrimitive() || fieldType.isArray() && fieldType.getComponentType().isPrimitive() ) |
| { |
| continue; |
| } |
| |
| visitor.visitClassDefine( !fieldType.isArray() ? fieldType : fieldType.getComponentType(), marshaller ); |
| if ( marshaller == null ) |
| { |
| visitFieldTypeAnnotatedProperties( !fieldType.isArray() ? fieldType : fieldType.getComponentType(), |
| visitor ); |
| } |
| } |
| } |
| |
| @SuppressWarnings( "unchecked" ) |
| private <F> void visitFieldTypeAnnotatedProperties( Class<?> type, DefinitionVisitor visitor ) |
| { |
| ClassBinder<F> classBinder = (ClassBinder<F>) buildClassBinder( type ); |
| new AnnotationBinderDefinition<F>( classBinder ).acceptVisitor( visitor ); |
| } |
| |
| private MarshallerContext combineMarshallers( AbstractSerializerDefinition abstractSerializerDefinition ) |
| { |
| return new InternalMarshallerContext( abstractSerializerDefinition.marshallerContext ); |
| } |
| } |
| |
| private abstract class DefinedAttributeBinder<V> |
| implements AttributeBinder<V> |
| { |
| |
| protected Marshaller marshaller; |
| |
| protected Field property; |
| |
| protected Class<?> declaringClass; |
| |
| protected void setDeclaringClass( Class<?> declaringClass ) |
| { |
| this.declaringClass = declaringClass; |
| } |
| |
| @Override |
| public AttributeBinder<V> using( Class<? extends Marshaller> marshaller ) |
| { |
| try |
| { |
| using( marshaller.newInstance() ); |
| return this; |
| } |
| catch ( Exception e ) |
| { |
| throw new SerializerDefinitionException( "Marshaller class " + marshaller.getCanonicalName() |
| + " could not be instantiated. Is there a standard (public) constructor?", e ); |
| } |
| } |
| |
| @Override |
| public AttributeBinder<V> using( Marshaller marshaller ) |
| { |
| if ( marshaller instanceof TypeBindableMarshaller ) |
| { |
| Type[] typeArguments = TypeUtil.getTypeArgument( property.getGenericType() ); |
| this.marshaller = ( (TypeBindableMarshaller) marshaller ).bindType( typeArguments ); |
| } |
| |
| return this; |
| } |
| |
| private void build() |
| { |
| if ( marshaller == null ) |
| { |
| marshaller = |
| definitionBuildingContext.getMarshallerStrategy().getMarshaller( property.getType(), |
| marshallerContext, true ); |
| } |
| propertyMarshallers.put( definitionBuildingContext.getPropertyDescriptorFactory().byField( property, |
| marshaller, |
| declaringClass ), |
| marshaller ); |
| } |
| } |
| } |