/* * Hibernate, Relational Persistence for Idiomatic Java * * Copyright (c) 2012, Red Hat, Inc. and/or its affiliates 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.search.test.id; import java.lang.annotation.Annotation; import java.util.Collections; import java.util.HashSet; 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.engine.spi.DocumentBuilderIndexedEntity; import org.hibernate.search.impl.ConfigContext; import org.hibernate.search.impl.SimpleInitializer; import org.hibernate.search.test.embedded.depth.PersonWithBrokenSocialSecurityNumber; import org.hibernate.search.test.util.ManualConfiguration; import org.hibernate.search.test.util.TestForIssue; 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</code> and <code>@DocumentId</code> * 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.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) { ManualConfiguration cfg = new ManualConfiguration(); ConfigContext context = new ConfigContext( cfg ); DocumentBuilderIndexedEntity docBuilder = new DocumentBuilderIndexedEntity(mappedXClass, context, null, reflectionManager, new HashSet(), SimpleInitializer.INSTANCE ); } /** * 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) { 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(); } } }