Package org.hibernate.metamodel.source.annotations

Source Code of org.hibernate.metamodel.source.annotations.ConfiguredClassHierarchy

/*
* 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;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import javax.persistence.AccessType;
import javax.persistence.InheritanceType;

import com.fasterxml.classmate.ResolvedTypeWithMembers;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.ClassInfo;
import org.jboss.jandex.FieldInfo;
import org.jboss.jandex.MethodInfo;

import org.hibernate.AnnotationException;
import org.hibernate.metamodel.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.source.annotations.util.ReflectionHelper;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.service.classloading.spi.ClassLoaderService;

/**
* Represents the inheritance structure of the configured classes within a class hierarchy.
*
* @author Hardy Ferentschik
*/
public class ConfiguredClassHierarchy implements Iterable<ConfiguredClass> {
  private final AccessType defaultAccessType;
  private final InheritanceType inheritanceType;
  private final List<ConfiguredClass> configuredClasses;

  public static ConfiguredClassHierarchy create(List<ClassInfo> classes, ServiceRegistry serviceRegistry) {
    return new ConfiguredClassHierarchy( classes, serviceRegistry );
  }

  private ConfiguredClassHierarchy(List<ClassInfo> classes, ServiceRegistry serviceRegistry) {
    defaultAccessType = determineDefaultAccessType( classes );
    inheritanceType = determineInheritanceType( classes );

    ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class );
    Class<?> clazz = classLoaderService.classForName( classes.get( classes.size() - 1 ).name().toString() );
    ResolvedTypeWithMembers resolvedMembers = ReflectionHelper.resolveMemberTypes( clazz );

    configuredClasses = new ArrayList<ConfiguredClass>();
    ConfiguredClass parent = null;
    for ( ClassInfo info : classes ) {
      ConfiguredClass configuredClass = new ConfiguredClass(
          info, parent, defaultAccessType, inheritanceType, serviceRegistry, resolvedMembers
      );
      configuredClasses.add( configuredClass );
      parent = configuredClass;
    }
  }

  public AccessType getDefaultAccessType() {
    return defaultAccessType;
  }

  public InheritanceType getInheritanceType() {
    return inheritanceType;
  }

  /**
   * @return An iterator iterating in top down manner over the configured classes in this hierarchy.
   */
  public Iterator<ConfiguredClass> iterator() {
    return configuredClasses.iterator();
  }

  @Override
  public String toString() {
    final StringBuilder sb = new StringBuilder();
    sb.append( "ConfiguredClassHierarchy" );
    sb.append( "{defaultAccessType=" ).append( defaultAccessType );
    sb.append( ", configuredClasses=" ).append( configuredClasses );
    sb.append( '}' );
    return sb.toString();
  }

  /**
   * @param classes the classes in the hierarchy
   *
   * @return Returns the default access type for the configured class hierarchy independent of explicit
   *         {@code AccessType} annotations. The default access type is determined by the placement of the
   *         annotations.
   */
  private AccessType determineDefaultAccessType(List<ClassInfo> classes) {
    AccessType accessType = null;
    for ( ClassInfo info : classes ) {
      List<AnnotationInstance> idAnnotations = info.annotations().get( JPADotNames.ID );
      if ( idAnnotations == null || idAnnotations.size() == 0 ) {
        continue;
      }
      accessType = processIdAnnotations( idAnnotations );
    }

    if ( accessType == null ) {
      return throwIdNotFoundAnnotationException( classes );
    }

    return accessType;
  }

  private AccessType processIdAnnotations(List<AnnotationInstance> idAnnotations) {
    AccessType accessType = null;
    for ( AnnotationInstance annotation : idAnnotations ) {
      AccessType tmpAccessType;
      if ( annotation.target() instanceof FieldInfo ) {
        tmpAccessType = AccessType.FIELD;
      }
      else if ( annotation.target() instanceof MethodInfo ) {
        tmpAccessType = AccessType.PROPERTY;
      }
      else {
        throw new AnnotationException( "Invalid placement of @Id annotation" );
      }

      if ( accessType == null ) {
        accessType = tmpAccessType;
      }
      else {
        if ( !accessType.equals( tmpAccessType ) ) {
          throw new AnnotationException( "Inconsistent placement of @Id annotation within hierarchy " );
        }
      }
    }
    return accessType;
  }

  private InheritanceType determineInheritanceType(List<ClassInfo> classes) {
    InheritanceType inheritanceType = null;
    for ( ClassInfo info : classes ) {
      AnnotationInstance inheritanceAnnotation = JandexHelper.getSingleAnnotation(
          info, JPADotNames.INHERITANCE
      );
      if ( inheritanceAnnotation == null ) {
        continue;
      }

      InheritanceType tmpInheritanceType = Enum.valueOf(
          InheritanceType.class, inheritanceAnnotation.value( "strategy" ).asEnum()
      );
      if ( tmpInheritanceType == null ) {
        // default inheritance type is single table
        inheritanceType = InheritanceType.SINGLE_TABLE;
      }

      if ( inheritanceType == null ) {
        inheritanceType = tmpInheritanceType;
      }
      else {
        if ( !inheritanceType.equals( tmpInheritanceType ) ) {
          throw new AnnotationException(
              "Multiple incompatible instances of @Inheritance specified within classes "
                  + hierarchyListString( classes )
          );
        }
      }
    }

    if ( inheritanceType == null ) {
      // default inheritance type is single table
      inheritanceType = InheritanceType.SINGLE_TABLE;
    }

    return inheritanceType;
  }

  private AccessType throwIdNotFoundAnnotationException(List<ClassInfo> classes) {
    StringBuilder builder = new StringBuilder();
    builder.append( "Unable to determine identifier attribute for class hierarchy " );
    builder.append( hierarchyListString( classes ) );
    throw new AnnotationException( builder.toString() );
  }

  private String hierarchyListString(List<ClassInfo> classes) {
    StringBuilder builder = new StringBuilder();
    builder.append( "[" );

    int count = 0;
    for ( ClassInfo info : classes ) {
      builder.append( info.name().toString() );
      if ( count < classes.size() - 1 ) {
        builder.append( ", " );
      }
      count++;
    }
    builder.append( "]" );
    return builder.toString();
  }
}

TOP

Related Classes of org.hibernate.metamodel.source.annotations.ConfiguredClassHierarchy

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.