org.hibernate.annotations.common.annotationfactory.AnnotationProxy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-commons-annotations Show documentation
Show all versions of hibernate-commons-annotations Show documentation
Common reflection code used in support of annotation processing
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2008, Red Hat Middleware LLC or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Middleware LLC.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.annotations.common.annotationfactory;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
/**
* A concrete implementation of Annotation
that pretends it is a
* "real" source code annotation. It's also an InvocationHandler
.
*
* When you create an AnnotationProxy
, you must initialize it
* with an AnnotationDescriptor
.
* The adapter checks that the provided elements are the same elements defined
* in the annotation interface. However, it does not check that their
* values are the right type. If you omit an element, the adapter will use the
* default value for that element from the annotation interface, if it exists.
* If no default exists, it will throw an exception.
*
* Warning: this class does not implement hashCode()
and
* equals()
- it just uses the ones it inherits from Object
.
* This means that an AnnotationProxy
does not follow the
* recommendations of the Annotation
javadoc about these two
* methods. That's why you should never mix AnnotationProxies
* with "real" annotations. For example, don't put them into the same
* Collection
.
*
* @author Paolo Perrotta
* @author Davide Marchignoli
* @see java.lang.annotation.Annotation
*/
public class AnnotationProxy implements Annotation, InvocationHandler {
private final Class extends Annotation> annotationType;
//FIXME it's probably better to use String as a key rather than Method
// to speed up and avoid any fancy permsize/GC issue
// I'd better check the litterature on the subject
private final Map values;
public AnnotationProxy(AnnotationDescriptor descriptor) {
this.annotationType = descriptor.type();
values = getAnnotationValues( descriptor );
}
private Map getAnnotationValues(AnnotationDescriptor descriptor) {
Map result = new HashMap();
int processedValuesFromDescriptor = 0;
for ( Method m : annotationType.getDeclaredMethods() ) {
if ( descriptor.containsElement( m.getName() ) ) {
result.put( m, descriptor.valueOf( m.getName() ) );
processedValuesFromDescriptor++;
}
else if ( m.getDefaultValue() != null ) {
result.put( m, m.getDefaultValue() );
}
else {
throw new IllegalArgumentException( "No value provided for " + m.getName() );
}
}
if ( processedValuesFromDescriptor != descriptor.numberOfElements() ) {
throw new RuntimeException( "Trying to instanciate " + annotationType + " with unknown elements" );
}
return result;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if ( values.containsKey( method ) ) {
return values.get( method );
}
return method.invoke( this, args );
}
public Class extends Annotation> annotationType() {
return annotationType;
}
public String toString() {
StringBuilder result = new StringBuilder();
result.append( '@' ).append( annotationType().getName() ).append( '(' );
for ( Method m : getRegisteredMethodsInAlphabeticalOrder() ) {
result.append( m.getName() ).append( '=' ).append( values.get( m ) ).append( ", " );
}
// remove last separator:
if ( values.size() > 0 ) {
result.delete( result.length() - 2, result.length() );
result.append( ")" );
}
else {
result.delete( result.length() - 1, result.length() );
}
return result.toString();
}
private SortedSet getRegisteredMethodsInAlphabeticalOrder() {
SortedSet result = new TreeSet(
new Comparator() {
public int compare(Method o1, Method o2) {
return o1.getName().compareTo( o2.getName() );
}
}
);
//List result = new LinkedList();
result.addAll( values.keySet() );
return result;
}
}