Package org.hibernate.metamodel.source.annotations.util

Source Code of org.hibernate.metamodel.source.annotations.util.JandexHelper

/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, Red Hat Inc. 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 Inc.
*
* 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.metamodel.source.annotations.util;

import java.beans.Introspector;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationTarget;
import org.jboss.jandex.AnnotationValue;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.DotName;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.Index;
import org.jboss.jandex.Indexer;
import org.jboss.jandex.MethodInfo;

import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException;
import org.hibernate.service.classloading.spi.ClassLoaderService;

/**
* Utility methods for working with the jandex annotation index.
*
* @author Hardy Ferentschik
*/
public class JandexHelper {
  private static final AnnotationInstance[] EMPTY_ANNOTATIONS_ARRAY = new AnnotationInstance[0];
  private static final Map<String, Object> DEFAULT_VALUES_BY_ELEMENT = new HashMap<String, Object>();

  private static Object getDefaultValue(AnnotationInstance annotation, String element) {
    String name = annotation.name().toString();
    String fqElement = name + '.' + element;
    Object val = DEFAULT_VALUES_BY_ELEMENT.get( fqElement );
    if ( val != null ) {
      return val;
    }
    try {
      val = Index.class.getClassLoader().loadClass( name ).getMethod( element ).getDefaultValue();
      DEFAULT_VALUES_BY_ELEMENT.put( fqElement, val );
      return val == null ? null : val;
    }
    catch ( RuntimeException error ) {
      throw error;
    }
    catch ( Exception error ) {
      throw new AnnotationException( error );
    }
  }

  /**
   * Expects a method or field annotation target and returns the property name for this target
   *
   * @param target the annotation target
   *
   * @return the property name of the target. For a field it is the field name and for a method name it is
   *         the method name stripped of 'is', 'has' or 'get'
   */
  public static String getPropertyName(AnnotationTarget target) {
    if ( !( target instanceof MethodInfo || target instanceof FieldInfo ) ) {
      throw new AssertionFailure( "Unexpected annotation target " + target.toString() );
    }

    if ( target instanceof FieldInfo ) {
      return ( (FieldInfo) target ).name();
    }
    else {
      final String methodName = ( (MethodInfo) target ).name();
      String propertyName;
      if ( methodName.startsWith( "is" ) ) {
        propertyName = Introspector.decapitalize( methodName.substring( 2 ) );
      }
      else if ( methodName.startsWith( "has" ) ) {
        propertyName = Introspector.decapitalize( methodName.substring( 3 ) );
      }
      else if ( methodName.startsWith( "get" ) ) {
        propertyName = Introspector.decapitalize( methodName.substring( 3 ) );
      }
      else {
        throw new AssertionFailure( "Expected a method following the Java Bean notation" );
      }
      return propertyName;
    }
  }

  /**
   * @param classInfo the class info from which to retrieve the annotation instance
   * @param annotationName the annotation to retrieve from the class info
   *
   * @return the single annotation defined on the class or {@code null} in case the annotation is not specified at all
   *
   * @throws org.hibernate.AssertionFailure in case there is there is more than one annotation of this type.
   */
  public static AnnotationInstance getSingleAnnotation(ClassInfo classInfo, DotName annotationName)
      throws AssertionFailure {
    return getSingleAnnotation( classInfo.annotations(), annotationName );
  }

  /**
   * @param annotations List of annotation instances keyed against their dot name.
   * @param annotationName the annotation to retrieve from map
   *
   * @return the single annotation of the specified dot name or {@code null} in case the annotation is not specified at all
   *
   * @throws org.hibernate.AssertionFailure in case there is there is more than one annotation of this type.
   */
  public static AnnotationInstance getSingleAnnotation(Map<DotName, List<AnnotationInstance>> annotations, DotName annotationName)
      throws AssertionFailure {
    List<AnnotationInstance> annotationList = annotations.get( annotationName );
    if ( annotationList == null ) {
      return null;
    }
    else if ( annotationList.size() == 1 ) {
      return annotationList.get( 0 );
    }
    else {
      throw new AssertionFailure(
          "Found more than one instance of the annotation "
              + annotationList.get( 0 ).name().toString()
              + ". Expected was one."
      );
    }
  }

  /**
   * Retrieves a jandex annotation element value.  If the value is <code>null</code>, the default value specified in the
   * annotation class is retrieved instead.  Note, {@link #getValueAsEnum(AnnotationInstance, String, Class)} must be
   * called to retrieve an enumerated value, and {@link #getValueAsArray(AnnotationInstance, String)} must be called to retrieve
   * an object array (other than a String array).
   *
   * @param annotation the annotation containing the element with the supplied name
   * @param element the name of the element value to be retrieve
   *
   * @return the value if not <code>null</code>, else the default value if not
   *         <code>null</code>, else <code>null</code>.
   */
  public static Object getValue(AnnotationInstance annotation, String element) {
    AnnotationValue val = annotation.value( element );
    if ( val == null ) {
      return getDefaultValue( annotation, element );
    }
    return val.asNested();
  }

  /**
   * Retrieves a jandex annotation element array.  Note, {@link #getValue(AnnotationInstance, String)} may be
   * called to retrieve a String array (or a non-array value).
   *
   * @param annotation the jandex annotation containing the element with the supplied name
   * @param element the name of the element array
   *
   * @return the element array if not <code>null</code>, else an empty array
   */
  public static AnnotationInstance[] getValueAsArray(AnnotationInstance annotation, String element) {
    AnnotationValue val = annotation.value( element );
    return val == null ? EMPTY_ANNOTATIONS_ARRAY : val.asNestedArray();
  }

  /**
   * Retrieves a jandex annotation element value, converting it to the supplied enumerated type.  If the value is
   * <code>null</code>, the default value specified in the annotation class is retrieved instead.
   *
   * @param <T> an enumerated type
   * @param annotation the annotation containing the enumerated element with the supplied name
   * @param element the name of the enumerated element value to be retrieve
   * @param type the type to which to convert the value before being returned
   *
   * @return the value converted to the supplied enumerated type if the value is not <code>null</code>, else the default value if
   *         not <code>null</code>, else <code>null</code>.
   *
   * @see #getValue(AnnotationInstance, String)
   */
  public static <T extends Enum<T>> T getValueAsEnum(AnnotationInstance annotation, String element, Class<T> type) {
    AnnotationValue val = annotation.value( element );
    if ( val == null ) {
      return (T) getDefaultValue( annotation, element );
    }
    return Enum.valueOf( type, val.asEnum() );
  }

  /**
   * Retrieves a jandex annotation element value as an Integer.  If the value is <code>null</code>, the default value specified in
   * the annotation class is retrieved instead.
   *
   * @param annotation the annotation containing the element with the supplied name
   * @param element the name of the element value to be retrieve
   *
   * @return the value converted to an int if the value is not <code>null</code>, else the default value if not
   *         <code>null</code>, else <code>0</code>.
   */
  public static int getValueAsInt(AnnotationInstance annotation, String element) {
    AnnotationValue val = annotation.value( element );
    if ( val == null ) {
      return (Integer) getDefaultValue( annotation, element );
    }
    return val.asInt();
  }

  /**
   * Retrieves a jandex annotation element value as a String.  If the value is <code>null</code>, the default value specified in
   * the annotation class is retrieved instead.
   *
   * @param annotation the annotation containing the element with the supplied name
   * @param element the name of the element value to be retrieve
   *
   * @return the value converted to a String if the value is not <code>null</code>, else the default value if not
   *         <code>null</code>, else <code>null</code>.
   */
  public static String getValueAsString(AnnotationInstance annotation, String element) {
    AnnotationValue val = annotation.value( element );
    if ( val == null ) {
      return (String) getDefaultValue( annotation, element );
    }
    return val.asString();
  }

  /**
   * Creates a jandex index for the specified classes
   *
   * @param classLoaderService class loader service
   * @param classes the classes to index
   *
   * @return an annotation repository w/ all the annotation discovered in the specified classes
   */
  public static Index indexForClass(ClassLoaderService classLoaderService, Class<?>... classes) {
    Indexer indexer = new Indexer();
    for ( Class<?> clazz : classes ) {
      InputStream stream = classLoaderService.locateResourceStream(
          clazz.getName().replace( '.', '/' ) + ".class"
      );
      try {
        indexer.index( stream );
      }
      catch ( IOException e ) {
        StringBuilder builder = new StringBuilder();
        builder.append( "[" );
        int count = 0;
        for ( Class<?> c : classes ) {
          builder.append( c.getName() );
          if ( count < classes.length - 1 ) {
            builder.append( "," );
          }
          count++;
        }
        builder.append( "]" );
        throw new HibernateException( "Unable to create annotation index for " + builder.toString() );
      }
    }
    return indexer.complete();
  }

  public static Map<DotName, List<AnnotationInstance>> getMemberAnnotations(ClassInfo classInfo, String name) {
    if ( classInfo == null ) {
      throw new IllegalArgumentException( "classInfo cannot be null" );
    }

    if ( name == null ) {
      throw new IllegalArgumentException( "name cannot be null" );
    }

    Map<DotName, List<AnnotationInstance>> annotations = new HashMap<DotName, List<AnnotationInstance>>();
    for ( List<AnnotationInstance> annotationList : classInfo.annotations().values() ) {
      for ( AnnotationInstance instance : annotationList ) {
        String targetName = null;
        if ( instance.target() instanceof FieldInfo ) {
          targetName = ( (FieldInfo) instance.target() ).name();
        }
        else if ( instance.target() instanceof MethodInfo ) {
          targetName = ( (MethodInfo) instance.target() ).name();
        }
        if ( targetName != null && name.equals( targetName ) ) {
          addAnnotationToMap( instance, annotations );
        }
      }
    }
    return annotations;
  }

  public static Map<DotName, List<AnnotationInstance>> getTypeAnnotations(ClassInfo classInfo) {
    if ( classInfo == null ) {
      throw new IllegalArgumentException( "classInfo cannot be null" );
    }

    Map<DotName, List<AnnotationInstance>> annotations = new HashMap<DotName, List<AnnotationInstance>>();
    for ( List<AnnotationInstance> annotationList : classInfo.annotations().values() ) {
      for ( AnnotationInstance instance : annotationList ) {
        if ( instance.target() instanceof ClassInfo ) {
          addAnnotationToMap( instance, annotations );
        }
      }
    }
    return annotations;
  }

  public static void addAnnotationToMap(AnnotationInstance instance, Map<DotName, List<AnnotationInstance>> annotations) {
    DotName dotName = instance.name();
    List<AnnotationInstance> list;
    if ( annotations.containsKey( dotName ) ) {
      list = annotations.get( dotName );
    }
    else {
      list = new ArrayList<AnnotationInstance>();
      annotations.put( dotName, list );
    }
    list.add( instance );
  }

  private JandexHelper() {
  }
}
TOP

Related Classes of org.hibernate.metamodel.source.annotations.util.JandexHelper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.