/** * Recursively constructs sets of audited and not audited properties and classes which behavior * has been overridden using {@link AuditOverride} annotation. * * @param clazz Class that is being processed. Currently mapped entity shall be passed during * first invocation. */ private void readAuditOverrides(XClass clazz) { /* TODO: Code to remove with @Audited.auditParents - start. */ final Audited allClassAudited = clazz.getAnnotation(Audited.class); if (allClassAudited != null && allClassAudited.auditParents().length > 0) { for (Class c : allClassAudited.auditParents()) { final XClass parentClass = reflectionManager.toXClass(c); checkSuperclass(clazz, parentClass); if (!overriddenNotAuditedClasses.contains(parentClass)) { // If the class has not been marked as not audited by the subclass. overriddenAuditedClasses.add(parentClass); } } } /* TODO: Code to remove with @Audited.auditParents - finish. */ final List<AuditOverride> auditOverrides = computeAuditOverrides(clazz); for (AuditOverride auditOverride : auditOverrides) { if (auditOverride.forClass() != void.class) { final XClass overrideClass = reflectionManager.toXClass(auditOverride.forClass()); checkSuperclass(clazz, overrideClass); final String propertyName = auditOverride.name(); if (!StringTools.isEmpty(propertyName)) { // Override @Audited annotation on property level. final XProperty property = getProperty(overrideClass, propertyName); if (auditOverride.isAudited()) { if (!overriddenNotAuditedProperties.contains(property)) { // If the property has not been marked as not audited by the subclass. overriddenAuditedProperties.add(property); } } else { if (!overriddenAuditedProperties.contains(property)) { // If the property has not been marked as audited by the subclass. overriddenNotAuditedProperties.add(property); } } } else { // Override @Audited annotation on class level. if (auditOverride.isAudited()) { if (!overriddenNotAuditedClasses.contains(overrideClass)) { // If the class has not been marked as not audited by the subclass. overriddenAuditedClasses.add(overrideClass); } } else { if (!overriddenAuditedClasses.contains(overrideClass)) { // If the class has not been marked as audited by the subclass. overriddenNotAuditedClasses.add(overrideClass); } } } } } final XClass superclass = clazz.getSuperclass(); if (!clazz.isInterface() && !Object.class.getName().equals(superclass.getName())) { readAuditOverrides(superclass); } }
public ClassAuditingData getAuditData() { if (pc.getClassName() == null) { return auditData; } try { XClass xclass = reflectionManager.classForName(pc.getClassName(), this.getClass()); ModificationStore defaultStore = getDefaultAudited(xclass); if (defaultStore != null) { auditData.setDefaultAudited(true); } new AuditedPropertiesReader( defaultStore, new PersistentClassPropertiesSource(xclass), auditData, globalCfg, reflectionManager, "") .read(); addAuditTable(xclass); addAuditSecondaryTables(xclass); } catch (ClassNotFoundException e) { throw new MappingException(e); } return auditData; }
public ComponentPropertiesSource(ReflectionManager reflectionManager, Component component) { try { this.xclass = reflectionManager.classForName(component.getComponentClassName(), this.getClass()); } catch (ClassNotFoundException e) { throw new MappingException(e); } this.component = component; }
private ContainerType getContainerType(XMember member, ReflectionManager reflectionManager) { if (!member.isAnnotationPresent(IndexedEmbedded.class)) { return ContainerType.SINGLE; } if (member.isArray()) { return ContainerType.ARRAY; } Class<?> typeClass = reflectionManager.toClass(member.getType()); if (Iterable.class.isAssignableFrom(typeClass)) { return ContainerType.ITERABLE; } if (member.isCollection() && Map.class.equals(member.getCollectionClass())) { return ContainerType.MAP; } // marked @IndexedEmbedded but not a container // => probably a @Field @IndexedEmbedded Foo foo; return ContainerType.SINGLE; }
/** * Constructor. * * @param xClass The class for which to build a document builder * @param typeMetadata metadata for the specified class * @param reflectionManager Reflection manager to use for processing the annotations * @param optimizationBlackList keeps track of types on which we need to disable collection events * optimizations * @param instanceInitializer a {@link org.hibernate.search.spi.InstanceInitializer} object. */ public AbstractDocumentBuilder( XClass xClass, TypeMetadata typeMetadata, ReflectionManager reflectionManager, Set<XClass> optimizationBlackList, InstanceInitializer instanceInitializer) { if (xClass == null) { throw new AssertionFailure( "Unable to build a DocumentBuilderContainedEntity with a null class"); } this.instanceInitializer = instanceInitializer; this.entityState = EntityState.CONTAINED_IN_ONLY; this.beanXClass = xClass; this.beanClass = reflectionManager.toClass(xClass); this.typeMetadata = typeMetadata; optimizationBlackList.addAll(typeMetadata.getOptimizationBlackList()); }
/** * This extracts and instantiates the implementation class from a ClassBridge annotation. * * @param fieldBridgeAnnotation the FieldBridge annotation * @param appliedOnType the type the bridge is applied on * @param reflectionManager The reflection manager instance * @return FieldBridge */ private FieldBridge extractType( org.hibernate.search.annotations.FieldBridge fieldBridgeAnnotation, XClass appliedOnType, ReflectionManager reflectionManager) { FieldBridge bridge = null; if (fieldBridgeAnnotation != null) { bridge = doExtractType( fieldBridgeAnnotation, appliedOnType.getName(), reflectionManager.toClass(appliedOnType)); } if (bridge == null) { throw LOG.unableToDetermineClassBridge(appliedOnType.getName()); } return bridge; }
private FieldBridge doExtractType( org.hibernate.search.annotations.FieldBridge bridgeAnn, XMember member, ReflectionManager reflectionManager) { return doExtractType(bridgeAnn, member.getName(), reflectionManager.toClass(member.getType())); }
public static Callback[] resolveCallback( XClass beanClass, Class annotation, ReflectionManager reflectionManager) { List<Callback> callbacks = new ArrayList<Callback>(); List<String> callbacksMethodNames = new ArrayList<String>(); // used to track overridden methods List<Class> orderedListeners = new ArrayList<Class>(); XClass currentClazz = beanClass; boolean stopListeners = false; boolean stopDefaultListeners = false; do { Callback callback = null; List<XMethod> methods = currentClazz.getDeclaredMethods(); final int size = methods.size(); for (int i = 0; i < size; i++) { final XMethod xMethod = methods.get(i); if (xMethod.isAnnotationPresent(annotation)) { Method method = reflectionManager.toMethod(xMethod); final String methodName = method.getName(); if (!callbacksMethodNames.contains(methodName)) { // overridden method, remove the superclass overridden method if (callback == null) { callback = new BeanCallback(method); Class returnType = method.getReturnType(); Class[] args = method.getParameterTypes(); if (returnType != Void.TYPE || args.length != 0) { throw new RuntimeException( "Callback methods annotated on the bean class must return void and take no arguments: " + annotation.getName() + " - " + xMethod); } if (!method.isAccessible()) method.setAccessible(true); LOG.debugf( "Adding %s as %s callback for entity %s", methodName, annotation.getSimpleName(), beanClass.getName()); callbacks.add(0, callback); // superclass first callbacksMethodNames.add(0, methodName); } else { throw new PersistenceException( "You can only annotate one callback method with " + annotation.getName() + " in bean class: " + beanClass.getName()); } } } } if (!stopListeners) { getListeners(currentClazz, orderedListeners); stopListeners = currentClazz.isAnnotationPresent(ExcludeSuperclassListeners.class); stopDefaultListeners = currentClazz.isAnnotationPresent(ExcludeDefaultListeners.class); } do { currentClazz = currentClazz.getSuperclass(); } while (currentClazz != null && !(currentClazz.isAnnotationPresent(Entity.class) || currentClazz.isAnnotationPresent(MappedSuperclass.class))); } while (currentClazz != null); // handle default listeners if (!stopDefaultListeners) { List<Class> defaultListeners = (List<Class>) reflectionManager.getDefaults().get(EntityListeners.class); if (defaultListeners != null) { int defaultListenerSize = defaultListeners.size(); for (int i = defaultListenerSize - 1; i >= 0; i--) { orderedListeners.add(defaultListeners.get(i)); } } } for (Class listener : orderedListeners) { Callback callback = null; if (listener != null) { XClass xListener = reflectionManager.toXClass(listener); callbacksMethodNames = new ArrayList<String>(); List<XMethod> methods = xListener.getDeclaredMethods(); final int size = methods.size(); for (int i = 0; i < size; i++) { final XMethod xMethod = methods.get(i); if (xMethod.isAnnotationPresent(annotation)) { final Method method = reflectionManager.toMethod(xMethod); final String methodName = method.getName(); if (!callbacksMethodNames.contains(methodName)) { // overridden method, remove the superclass overridden method if (callback == null) { try { callback = new ListenerCallback(method, listener.newInstance()); } catch (IllegalAccessException e) { throw new PersistenceException( "Unable to create instance of " + listener.getName() + " as a listener of beanClass", e); } catch (InstantiationException e) { throw new PersistenceException( "Unable to create instance of " + listener.getName() + " as a listener of beanClass", e); } Class returnType = method.getReturnType(); Class[] args = method.getParameterTypes(); if (returnType != Void.TYPE || args.length != 1) { throw new PersistenceException( "Callback methods annotated in a listener bean class must return void and take one argument: " + annotation.getName() + " - " + method); } if (!method.isAccessible()) method.setAccessible(true); LOG.debugf( "Adding %s as %s callback for entity %s", methodName, annotation.getSimpleName(), beanClass.getName()); callbacks.add(0, callback); // listeners first } else { throw new PersistenceException( "You can only annotate one callback method with " + annotation.getName() + " in bean class: " + beanClass.getName() + " and callback listener: " + listener.getName()); } } } } } } return callbacks.toArray(new Callback[callbacks.size()]); }
public RevisionInfoConfigurationResult configure( Configuration cfg, ReflectionManager reflectionManager) { Iterator<PersistentClass> classes = (Iterator<PersistentClass>) cfg.getClassMappings(); boolean revisionEntityFound = false; RevisionInfoGenerator revisionInfoGenerator = null; Class<?> revisionInfoClass = null; while (classes.hasNext()) { PersistentClass pc = classes.next(); XClass clazz; try { clazz = reflectionManager.classForName(pc.getClassName(), this.getClass()); } catch (ClassNotFoundException e) { throw new MappingException(e); } RevisionEntity revisionEntity = clazz.getAnnotation(RevisionEntity.class); if (revisionEntity != null) { if (revisionEntityFound) { throw new MappingException("Only one entity may be annotated with @RevisionEntity!"); } // Checking if custom revision entity isn't audited if (clazz.getAnnotation(Audited.class) != null) { throw new MappingException("An entity annotated with @RevisionEntity cannot be audited!"); } revisionEntityFound = true; MutableBoolean revisionNumberFound = new MutableBoolean(); MutableBoolean revisionTimestampFound = new MutableBoolean(); MutableBoolean modifiedEntityNamesFound = new MutableBoolean(); searchForRevisionInfoCfg( clazz, reflectionManager, revisionNumberFound, revisionTimestampFound, modifiedEntityNamesFound); if (!revisionNumberFound.isSet()) { throw new MappingException( "An entity annotated with @RevisionEntity must have a field annotated " + "with @RevisionNumber!"); } if (!revisionTimestampFound.isSet()) { throw new MappingException( "An entity annotated with @RevisionEntity must have a field annotated " + "with @RevisionTimestamp!"); } revisionInfoEntityName = pc.getEntityName(); revisionInfoClass = pc.getMappedClass(); Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(revisionEntity.value()); revisionInfoTimestampType = pc.getProperty(revisionInfoTimestampData.getName()).getType(); if (globalCfg.isTrackEntitiesChangedInRevisionEnabled() || DefaultTrackingModifiedEntitiesRevisionEntity.class.isAssignableFrom( revisionInfoClass) || modifiedEntityNamesFound.isSet()) { // If tracking modified entities parameter is enabled, custom revision info entity is a // subtype // of DefaultTrackingModifiedEntitiesRevisionEntity class, or @ModifiedEntityNames // annotation is used. revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator( revisionInfoEntityName, revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData); globalCfg.setTrackEntitiesChangedInRevisionEnabled(true); } else { revisionInfoGenerator = new DefaultRevisionInfoGenerator( revisionInfoEntityName, revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()); } } } // In case of a custom revision info generator, the mapping will be null. Document revisionInfoXmlMapping = null; Class<? extends RevisionListener> revisionListenerClass = getRevisionListenerClass(RevisionListener.class); if (revisionInfoGenerator == null) { if (globalCfg.isTrackEntitiesChangedInRevisionEnabled()) { revisionInfoClass = DefaultTrackingModifiedEntitiesRevisionEntity.class; revisionInfoEntityName = DefaultTrackingModifiedEntitiesRevisionEntity.class.getName(); revisionInfoGenerator = new DefaultTrackingModifiedEntitiesRevisionInfoGenerator( revisionInfoEntityName, revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate(), modifiedEntityNamesData); } else { revisionInfoClass = DefaultRevisionEntity.class; revisionInfoGenerator = new DefaultRevisionInfoGenerator( revisionInfoEntityName, revisionInfoClass, revisionListenerClass, revisionInfoTimestampData, isTimestampAsDate()); } revisionInfoXmlMapping = generateDefaultRevisionInfoXmlMapping(); } return new RevisionInfoConfigurationResult( revisionInfoGenerator, revisionInfoXmlMapping, new RevisionInfoQueryCreator( revisionInfoEntityName, revisionInfoIdData.getName(), revisionInfoTimestampData.getName(), isTimestampAsDate()), generateRevisionInfoRelationMapping(), new RevisionInfoNumberReader(revisionInfoClass, revisionInfoIdData), globalCfg.isTrackEntitiesChangedInRevisionEnabled() ? new ModifiedEntityNamesReader(revisionInfoClass, modifiedEntityNamesData) : null, revisionInfoEntityName, revisionInfoClass, revisionInfoTimestampData); }
private void searchForRevisionInfoCfgInProperties( XClass clazz, ReflectionManager reflectionManager, MutableBoolean revisionNumberFound, MutableBoolean revisionTimestampFound, MutableBoolean modifiedEntityNamesFound, String accessType) { for (XProperty property : clazz.getDeclaredProperties(accessType)) { RevisionNumber revisionNumber = property.getAnnotation(RevisionNumber.class); RevisionTimestamp revisionTimestamp = property.getAnnotation(RevisionTimestamp.class); ModifiedEntityNames modifiedEntityNames = property.getAnnotation(ModifiedEntityNames.class); if (revisionNumber != null) { if (revisionNumberFound.isSet()) { throw new MappingException("Only one property may be annotated with @RevisionNumber!"); } XClass revisionNumberClass = property.getType(); if (reflectionManager.equals(revisionNumberClass, Integer.class) || reflectionManager.equals(revisionNumberClass, Integer.TYPE)) { revisionInfoIdData = new PropertyData(property.getName(), property.getName(), accessType, null); revisionNumberFound.set(); } else if (reflectionManager.equals(revisionNumberClass, Long.class) || reflectionManager.equals(revisionNumberClass, Long.TYPE)) { revisionInfoIdData = new PropertyData(property.getName(), property.getName(), accessType, null); revisionNumberFound.set(); // The default is integer revisionPropType = "long"; } else { throw new MappingException( "The field annotated with @RevisionNumber must be of type " + "int, Integer, long or Long"); } // Getting the @Column definition of the revision number property, to later use that info to // generate the same mapping for the relation from an audit table's revision number to the // revision entity revision number. Column revisionPropColumn = property.getAnnotation(Column.class); if (revisionPropColumn != null) { revisionPropSqlType = revisionPropColumn.columnDefinition(); } } if (revisionTimestamp != null) { if (revisionTimestampFound.isSet()) { throw new MappingException("Only one property may be annotated with @RevisionTimestamp!"); } XClass revisionTimestampClass = property.getType(); if (reflectionManager.equals(revisionTimestampClass, Long.class) || reflectionManager.equals(revisionTimestampClass, Long.TYPE) || reflectionManager.equals(revisionTimestampClass, Date.class) || reflectionManager.equals(revisionTimestampClass, java.sql.Date.class)) { revisionInfoTimestampData = new PropertyData(property.getName(), property.getName(), accessType, null); revisionTimestampFound.set(); } else { throw new MappingException( "The field annotated with @RevisionTimestamp must be of type " + "long, Long, java.util.Date or java.sql.Date"); } } if (modifiedEntityNames != null) { if (modifiedEntityNamesFound.isSet()) { throw new MappingException( "Only one property may be annotated with @ModifiedEntityNames!"); } XClass modifiedEntityNamesClass = property.getType(); if (reflectionManager.equals(modifiedEntityNamesClass, Set.class) && reflectionManager.equals(property.getElementClass(), String.class)) { modifiedEntityNamesData = new PropertyData(property.getName(), property.getName(), accessType, null); modifiedEntityNamesFound.set(); } else { throw new MappingException( "The field annotated with @ModifiedEntityNames must be of Set<String> type."); } } } }