/* * Hibernate Search, full-text search for your domain model * * License: GNU Lesser General Public License (LGPL), version 2.1 or later * See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>. */ package org.hibernate.search.test.id; import java.lang.annotation.Annotation; import java.util.Collections; import java.util.List; import org.hibernate.annotations.common.reflection.Filter; import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XMethod; import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.annotations.common.reflection.java.JavaReflectionManager; import org.hibernate.search.cfg.spi.SearchConfiguration; import org.hibernate.search.engine.impl.ConfigContext; import org.hibernate.search.engine.metadata.impl.AnnotationMetadataProvider; import org.hibernate.search.engine.metadata.impl.MetadataProvider; import org.hibernate.search.engine.metadata.impl.TypeMetadata; import org.hibernate.search.engine.spi.DocumentBuilderIndexedEntity; import org.hibernate.search.indexes.spi.LuceneEmbeddedIndexManagerType; import org.hibernate.search.spi.DefaultInstanceInitializer; import org.hibernate.search.test.embedded.depth.PersonWithBrokenSocialSecurityNumber; import org.hibernate.search.test.util.HibernateManualConfiguration; import org.hibernate.search.testsupport.TestForIssue; import org.hibernate.search.testsupport.setup.BuildContextForTest; import org.junit.Test; /** * The order in which the XClass methods will be listed varies depending on the platform and JVM, * in particular we had an issue with annotations {@code @Id} and {@code @DocumentId} * when encountering them in unexpected order. This test verifies iteration order doesn't affect * our capability to startup correctly. * * @author Sanne Grinovero */ @TestForIssue(jiraKey = "HSEARCH-1048") public class UnorderedIdScanTest { @Test public void naturalSortAnnotationsRead() { ReflectionManager reflectionManager = new JavaReflectionManager(); XClass mappedXClass = reflectionManager.toXClass( PersonWithBrokenSocialSecurityNumber.class ); tryCreatingDocumentBuilder( mappedXClass, reflectionManager ); //No assertions needed: we just verify the previous statements won't throw an exception } @Test public void invertedSortAnnotationsRead() { JavaReflectionManager reflectionManager = new TrickedJavaReflectionManager<PersonWithBrokenSocialSecurityNumber>( PersonWithBrokenSocialSecurityNumber.class ); XClass mappedXClass = reflectionManager.toXClass( PersonWithBrokenSocialSecurityNumber.class ); XClass reverted = new DeclaredMethodsReverter( mappedXClass ); tryCreatingDocumentBuilder( reverted, reflectionManager ); //No assertions needed: we just verify the previous statements won't throw an exception } private static void tryCreatingDocumentBuilder(XClass mappedXClass, ReflectionManager reflectionManager) { SearchConfiguration searchConfiguration = new HibernateManualConfiguration(); ConfigContext context = new ConfigContext( searchConfiguration, new BuildContextForTest( searchConfiguration ) ); MetadataProvider metadataProvider = new AnnotationMetadataProvider( reflectionManager, context ); TypeMetadata typeMetadata = metadataProvider.getTypeMetadataFor( reflectionManager.toClass( mappedXClass ), LuceneEmbeddedIndexManagerType.INSTANCE ); new DocumentBuilderIndexedEntity( mappedXClass, typeMetadata, context, reflectionManager, Collections.<XClass>emptySet(), DefaultInstanceInitializer.DEFAULT_INITIALIZER ); } /** * The real JavaReflectionManager would throw an error when the toClass method is invoked on an XClass * instance it didn't create, so we trick that. */ static class TrickedJavaReflectionManager<T> extends JavaReflectionManager { private final Class<T> class1; public TrickedJavaReflectionManager(Class<T> class1) { this.class1 = class1; } @Override public Class toClass(XClass xClazz) { try { return super.toClass( xClazz ); } catch (IllegalArgumentException e) { return class1; } } @Override public boolean equals(XClass class1, Class class2) { if ( class1 instanceof DeclaredMethodsReverter ) { DeclaredMethodsReverter wrapper = (DeclaredMethodsReverter) class1; return super.equals( wrapper.delegate, class2 ); } else { return super.equals( class1, class2 ); } } } /** * Delegate all methods to a wrapped XClass instance but revert the order * of properties when listing them. */ static class DeclaredMethodsReverter implements XClass { private final XClass delegate; DeclaredMethodsReverter(XClass delegate) { this.delegate = delegate; } @Override public <T extends Annotation> T getAnnotation(Class<T> arg0) { return delegate.getAnnotation( arg0 ); } @Override public Annotation[] getAnnotations() { return delegate.getAnnotations(); } @Override public <T extends Annotation> boolean isAnnotationPresent(Class<T> arg0) { return delegate.isAnnotationPresent( arg0 ); } @Override public List<XMethod> getDeclaredMethods() { List<XMethod> declaredMethods = delegate.getDeclaredMethods(); Collections.reverse( declaredMethods ); return declaredMethods; } @Override public List<XProperty> getDeclaredProperties(String arg0) { List<XProperty> declaredProperties = delegate.getDeclaredProperties( arg0 ); Collections.reverse( declaredProperties ); return declaredProperties; } @Override public List<XProperty> getDeclaredProperties(String arg0, Filter arg1) { List<XProperty> declaredProperties = delegate.getDeclaredProperties( arg0, arg1 ); Collections.reverse( declaredProperties ); return declaredProperties; } @Override public XClass[] getInterfaces() { return delegate.getInterfaces(); } @Override public String getName() { return delegate.getName(); } @Override public XClass getSuperclass() { return delegate.getSuperclass(); } @Override public boolean isAbstract() { return delegate.isAbstract(); } @Override public boolean isAssignableFrom(XClass arg0) { return delegate.isAssignableFrom( arg0 ); } @Override public boolean isEnum() { return delegate.isEnum(); } @Override public boolean isInterface() { return delegate.isInterface(); } @Override public boolean isPrimitive() { return delegate.isPrimitive(); } } }