/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ package org.apache.openjpa.persistence; import java.io.Serializable; import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; import java.lang.reflect.Field; import java.lang.reflect.Member; import java.lang.reflect.Method; import java.lang.reflect.Modifier; import java.security.AccessController; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import java.util.List; import java.util.ArrayList; import java.util.Locale; import javax.persistence.Access; import javax.persistence.AccessType; import javax.persistence.Basic; import javax.persistence.ElementCollection; import javax.persistence.Embeddable; import javax.persistence.Embedded; import javax.persistence.EmbeddedId; import javax.persistence.ManyToMany; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.OneToOne; import javax.persistence.PostLoad; import javax.persistence.PostPersist; import javax.persistence.PostRemove; import javax.persistence.PostUpdate; import javax.persistence.PrePersist; import javax.persistence.PreRemove; import javax.persistence.PreUpdate; import javax.persistence.Transient; import org.apache.openjpa.lib.util.J2DoPrivHelper; import org.apache.openjpa.lib.util.Localizer; import org.apache.openjpa.lib.log.Log; import org.apache.openjpa.meta.AbstractMetaDataDefaults; import org.apache.openjpa.meta.AccessCode; import org.apache.openjpa.meta.ClassMetaData; import org.apache.openjpa.meta.FieldMetaData; import org.apache.openjpa.meta.JavaTypes; import org.apache.openjpa.meta.MetaDataRepository; import org.apache.openjpa.meta.ValueMetaData; import static javax.persistence.AccessType.FIELD; import static javax.persistence.AccessType.PROPERTY; import static org.apache.openjpa.persistence.PersistenceStrategy.*; import org.apache.openjpa.util.InternalException; import org.apache.openjpa.util.MetaDataException; import org.apache.openjpa.util.UserException; import org.apache.openjpa.conf.OpenJPAConfiguration; import org.apache.openjpa.enhance.Reflection; /** * JPA-based metadata defaults. * * @author Patrick Linskey * @author Abe White * @author Pinaki Poddar */ public class PersistenceMetaDataDefaults extends AbstractMetaDataDefaults { private static final Localizer _loc = Localizer.forPackage (PersistenceMetaDataDefaults.class); private static final Map<Class<?>, PersistenceStrategy> _strats = new HashMap<Class<?>, PersistenceStrategy>(); private static final Set<String> _ignoredAnnos = new HashSet<String>(); static { _strats.put(Basic.class, BASIC); _strats.put(ManyToOne.class, MANY_ONE); _strats.put(OneToOne.class, ONE_ONE); _strats.put(Embedded.class, EMBEDDED); _strats.put(EmbeddedId.class, EMBEDDED); _strats.put(OneToMany.class, ONE_MANY); _strats.put(ManyToMany.class, MANY_MANY); _strats.put(Persistent.class, PERS); _strats.put(PersistentCollection.class, PERS_COLL); _strats.put(ElementCollection.class, ELEM_COLL); _strats.put(PersistentMap.class, PERS_MAP); _ignoredAnnos.add(DetachedState.class.getName()); _ignoredAnnos.add(PostLoad.class.getName()); _ignoredAnnos.add(PostPersist.class.getName()); _ignoredAnnos.add(PostRemove.class.getName()); _ignoredAnnos.add(PostUpdate.class.getName()); _ignoredAnnos.add(PrePersist.class.getName()); _ignoredAnnos.add(PreRemove.class.getName()); _ignoredAnnos.add(PreUpdate.class.getName()); } /** * Set of Inclusion Filters based on member type, access type or transient * annotations. Used to determine the persistent field/methods. */ protected AccessFilter propertyAccessFilter = new AccessFilter(PROPERTY); protected AccessFilter fieldAccessFilter = new AccessFilter(FIELD); protected MemberFilter fieldFilter = new MemberFilter(Field.class); protected MemberFilter methodFilter = new MemberFilter(Method.class); protected TransientFilter nonTransientFilter = new TransientFilter(false); protected AnnotatedFilter annotatedFilter = new AnnotatedFilter(); protected GetterFilter getterFilter = new GetterFilter(); protected SetterFilter setterFilter = new SetterFilter(); private Boolean _isAbstractMappingUniDirectional = null; private Boolean _isNonDefaultMappingAllowed = null; private String _defaultSchema; private Boolean _isCascadePersistPersistenceUnitDefaultEnabled = null; public PersistenceMetaDataDefaults() { setCallbackMode(CALLBACK_RETHROW | CALLBACK_ROLLBACK | CALLBACK_FAIL_FAST); setDataStoreObjectIdFieldUnwrapped(true); } /** * Return the code for the strategy of the given member. Return null if * no strategy. */ public static PersistenceStrategy getPersistenceStrategy (FieldMetaData fmd, Member member) { return getPersistenceStrategy(fmd, member, false); } /** * Return the code for the strategy of the given member. Return null if * no strategy. */ public static PersistenceStrategy getPersistenceStrategy (FieldMetaData fmd, Member member, boolean ignoreTransient) { if (member == null) return null; AnnotatedElement el = (AnnotatedElement) member; if (!ignoreTransient && (AccessController.doPrivileged(J2DoPrivHelper .isAnnotationPresentAction(el, Transient.class))).booleanValue()) return TRANSIENT; if (fmd != null && fmd.getManagement() != FieldMetaData.MANAGE_PERSISTENT) return null; // look for persistence strategy in annotation table PersistenceStrategy pstrat = null; for (Annotation anno : el.getDeclaredAnnotations()) { if (pstrat != null && _strats.containsKey(anno.annotationType())) throw new MetaDataException(_loc.get("already-pers", member)); if (pstrat == null) pstrat = _strats.get(anno.annotationType()); } if (pstrat != null) return pstrat; Class type; int code; if (fmd != null) { type = fmd.getType(); code = fmd.getTypeCode(); } else if (member instanceof Field) { type = ((Field) member).getType(); code = JavaTypes.getTypeCode(type); } else { type = ((Method) member).getReturnType(); code = JavaTypes.getTypeCode(type); } switch (code) { case JavaTypes.ARRAY: if (type == byte[].class || type == char[].class || type == Byte[].class || type == Character[].class) return BASIC; break; case JavaTypes.BOOLEAN: case JavaTypes.BOOLEAN_OBJ: case JavaTypes.BYTE: case JavaTypes.BYTE_OBJ: case JavaTypes.CHAR: case JavaTypes.CHAR_OBJ: case JavaTypes.DOUBLE: case JavaTypes.DOUBLE_OBJ: case JavaTypes.FLOAT: case JavaTypes.FLOAT_OBJ: case JavaTypes.INT: case JavaTypes.INT_OBJ: case JavaTypes.LONG: case JavaTypes.LONG_OBJ: case JavaTypes.SHORT: case JavaTypes.SHORT_OBJ: case JavaTypes.STRING: case JavaTypes.BIGDECIMAL: case JavaTypes.BIGINTEGER: case JavaTypes.DATE: return BASIC; case JavaTypes.OBJECT: if (Enum.class.isAssignableFrom(type)) return BASIC; break; } //### EJB3: what if defined in XML? if ((AccessController.doPrivileged(J2DoPrivHelper .isAnnotationPresentAction(type, Embeddable.class))).booleanValue()) return EMBEDDED; if (Serializable.class.isAssignableFrom(type)) return BASIC; return null; } /** * Auto-configuration method for the default access type of base classes * with ACCESS_UNKNOWN */ public void setDefaultAccessType(String type) { if ("PROPERTY".equals(type.toUpperCase(Locale.ENGLISH))) setDefaultAccessType(AccessCode.PROPERTY); else if ("FIELD".equals(type.toUpperCase(Locale.ENGLISH))) setDefaultAccessType(AccessCode.FIELD); else throw new IllegalArgumentException(_loc.get("access-invalid", type).toString()); } /** * Populates the given class metadata. The access style determines which * field and/or getter method will contribute as the persistent property * of the given class. If the given access is unknown, then the access * type is to be determined at first. * * @see #determineAccessType(ClassMetaData) */ @Override public void populate(ClassMetaData meta, int access) { populate(meta, access, false); } /** * Populates the given class metadata. The access style determines which * field and/or getter method will contribute as the persistent property * of the given class. If the given access is unknown, then the access * type is to be determined at first. * * @see #determineAccessType(ClassMetaData) */ @Override public void populate(ClassMetaData meta, int access, boolean ignoreTransient) { if (AccessCode.isUnknown(access)) { access = determineAccessType(meta); } if (AccessCode.isUnknown(access)) { error(meta, _loc.get("access-unknown", meta)); } super.populate(meta, access, ignoreTransient); meta.setDetachable(true); // do not call get*Fields as it will lock down the fields. } @Override protected void populate(FieldMetaData fmd) { setCascadeNone(fmd); setCascadeNone(fmd.getKey()); setCascadeNone(fmd.getElement()); } /** * Turns off auto cascading of persist, refresh, attach, detach. */ static void setCascadeNone(ValueMetaData vmd) { vmd.setCascadePersist(ValueMetaData.CASCADE_NONE); vmd.setCascadeRefresh(ValueMetaData.CASCADE_NONE); vmd.setCascadeAttach(ValueMetaData.CASCADE_NONE); vmd.setCascadeDetach(ValueMetaData.CASCADE_NONE); } ClassMetaData getCachedSuperclassMetaData(ClassMetaData meta) { if (meta == null) return null; Class<?> cls = meta.getDescribedType(); Class<?> sup = cls.getSuperclass(); if (sup == null || "java.lang.Object".equals( sup.getName())) return null; MetaDataRepository repos = meta.getRepository(); ClassMetaData supMeta = repos.getCachedMetaData(sup); if (supMeta == null) supMeta = repos.getMetaData(sup, null, false); return supMeta; } /** * Recursive helper to determine access type based on annotation placement * on members for the given class without an explicit access annotation. * * @return must return a not-unknown access code */ private int determineAccessType(ClassMetaData meta) { if (meta == null) return AccessCode.UNKNOWN; if (meta.getDescribedType().isInterface()) // managed interfaces return AccessCode.PROPERTY; if (!AccessCode.isUnknown(meta)) return meta.getAccessType(); int access = determineExplicitAccessType(meta.getDescribedType()); if (!AccessCode.isUnknown(access)) return access; access = determineImplicitAccessType(meta.getDescribedType(), meta.getRepository().getConfiguration()); if (!AccessCode.isUnknown(access)) return access; ClassMetaData sup = getCachedSuperclassMetaData(meta); ClassMetaData tmpSup = sup; while (tmpSup != null && tmpSup.isExplicitAccess()) { tmpSup = getCachedSuperclassMetaData(tmpSup); if (tmpSup != null) { sup = tmpSup; } } if (sup != null && !AccessCode.isUnknown(sup)) return sup.getAccessType(); trace(meta, _loc.get("access-default", meta, AccessCode.toClassString(getDefaultAccessType()))); return getDefaultAccessType(); } /** * Determines the access type for the given class by placement of * annotations on field or getter method. Does not consult the * super class. * * Annotation can be placed on either fields or getters but not on both. * If no field or getter is annotated then UNKNOWN access code is returned. */ private int determineImplicitAccessType(Class<?> cls, OpenJPAConfiguration conf) { if (cls.isInterface()) // Managed interfaces return AccessCode.PROPERTY; Field[] allFields = AccessController.doPrivileged(J2DoPrivHelper. getDeclaredFieldsAction(cls)); Method[] methods = AccessController.doPrivileged( J2DoPrivHelper.getDeclaredMethodsAction(cls)); List<Field> fields = filter(allFields, new TransientFilter(true)); /* * OpenJPA 1.x permitted private properties to be persistent. This is * contrary to the JPA 1.0 specification, which states that persistent * properties must be public or protected. OpenJPA 2.0+ will adhere * to the specification by default, but provides a compatibility * option to provide pre-2.0 behavior. */ getterFilter.setIncludePrivate( conf.getCompatibilityInstance().getPrivatePersistentProperties()); List<Method> getters = filter(methods, getterFilter); if (fields.isEmpty() && getters.isEmpty()) return AccessCode.EMPTY; fields = filter(fields, annotatedFilter); getters = filter(getters, annotatedFilter); List<Method> setters = filter(methods, setterFilter); getters = matchGetterAndSetter(getters, setters); boolean mixed = !fields.isEmpty() && !getters.isEmpty(); if (mixed) throw new UserException(_loc.get("access-mixed", cls, toFieldNames(fields), toMethodNames(getters))); if (!fields.isEmpty()) { return AccessCode.FIELD; } if (!getters.isEmpty()) { return AccessCode.PROPERTY; } return AccessCode.UNKNOWN; } /** * Explicit access type, if any, is generally detected by the parser. This * is only used for metadata of an embeddable type which is encountered * as a field during some other owning entity. * * @see ValueMetaData#addEmbeddedMetaData() */ private int determineExplicitAccessType(Class<?> cls) { Access access = cls.getAnnotation(Access.class); return access == null ? AccessCode.UNKNOWN : ((access.value() == AccessType.FIELD ? AccessCode.FIELD : AccessCode.PROPERTY) | AccessCode.EXPLICIT); } /** * Matches the given getters with the given setters. Removes the getters * that do not have a corresponding setter. */ private List<Method> matchGetterAndSetter(List<Method> getters, List<Method> setters) { Collection<Method> unmatched = new ArrayList<Method>(); for (Method getter : getters) { String getterName = getter.getName(); Class<?> getterReturnType = getter.getReturnType(); String expectedSetterName = "set" + getterName.substring( (isBooleanGetter(getter) ? "is" : "get").length()); boolean matched = false; for (Method setter : setters) { Class<?> setterArgType = setter.getParameterTypes()[0]; String actualSetterName = setter.getName(); matched = actualSetterName.equals(expectedSetterName) && setterArgType == getterReturnType; if (matched) break; } if (!matched) { unmatched.add(getter); } } getters.removeAll(unmatched); return getters; } /** * Gets the fields that are possible candidate for being persisted. The * result depends on the current access style of the given class. */ List<Field> getPersistentFields(ClassMetaData meta, boolean ignoreTransient) { boolean explicit = meta.isExplicitAccess(); boolean unknown = AccessCode.isUnknown(meta); boolean isField = AccessCode.isField(meta); if (explicit || unknown || isField) { Field[] fields = AccessController.doPrivileged(J2DoPrivHelper. getDeclaredFieldsAction(meta.getDescribedType())); return filter(fields, fieldFilter, ignoreTransient ? null : nonTransientFilter, unknown || isField ? null : annotatedFilter, explicit ? (isField ? null : fieldAccessFilter) : null); } return Collections.EMPTY_LIST; } /** * Gets the methods that are possible candidate for being persisted. The * result depends on the current access style of the given class. */ List<Method> getPersistentMethods(ClassMetaData meta, boolean ignoreTransient) { boolean explicit = meta.isExplicitAccess(); boolean unknown = AccessCode.isUnknown(meta.getAccessType()); boolean isProperty = AccessCode.isProperty(meta.getAccessType()); if (explicit || unknown || isProperty) { Method[] publicMethods = AccessController.doPrivileged( J2DoPrivHelper.getDeclaredMethodsAction(meta.getDescribedType())); /* * OpenJPA 1.x permitted private accessor properties to be persistent. This is * contrary to the JPA 1.0 specification, which states that persistent * properties must be public or protected. OpenJPA 2.0+ will adhere * to the specification by default, but provides a compatibility * option to provide pre-2.0 behavior. */ getterFilter.setIncludePrivate( meta.getRepository().getConfiguration().getCompatibilityInstance().getPrivatePersistentProperties()); List<Method> getters = filter(publicMethods, methodFilter, getterFilter, ignoreTransient ? null : nonTransientFilter, unknown || isProperty ? null : annotatedFilter, explicit ? (isProperty ? null : propertyAccessFilter) : null); List<Method> setters = filter(publicMethods, setterFilter); return getters = matchGetterAndSetter(getters, setters); } return Collections.EMPTY_LIST; } /** * Gets the members that are backing members for attributes being persisted. * Unlike {@linkplain #getPersistentFields(ClassMetaData)} and * {@linkplain #getPersistentMethods(ClassMetaData)} which returns * <em>possible</em> candidates, the result of this method is definite. * * Side-effect of this method is if the given class metadata has * no access type set, this method will set it. */ @Override public List<Member> getPersistentMembers(ClassMetaData meta, boolean ignoreTransient) { List<Member> members = new ArrayList<Member>(); List<Field> fields = getPersistentFields(meta, ignoreTransient); List<Method> getters = getPersistentMethods(meta, ignoreTransient); boolean isMixed = !fields.isEmpty() && !getters.isEmpty(); boolean isEmpty = fields.isEmpty() && getters.isEmpty(); boolean explicit = meta.isExplicitAccess(); boolean unknown = AccessCode.isUnknown(meta.getAccessType()); if (isEmpty) { warn(meta, _loc.get("access-empty", meta)); return Collections.EMPTY_LIST; } if (explicit) { if (isMixed) { assertNoDuplicate(fields, getters); meta.setAccessType(AccessCode.MIXED | meta.getAccessType()); members.addAll(fields); members.addAll(getters); } else { members.addAll(fields.isEmpty() ? getters : fields); } } else { if (isMixed) error(meta, _loc.get("access-mixed", meta, fields, getters)); if (fields.isEmpty()) { meta.setAccessType(AccessCode.PROPERTY); members.addAll(getters); } else { meta.setAccessType(AccessCode.FIELD); members.addAll(fields); } } return members; } void assertNoDuplicate(List<Field> fields, List<Method> getters) { } void error(ClassMetaData meta, Localizer.Message message) { Log log = meta.getRepository().getConfiguration() .getLog(OpenJPAConfiguration.LOG_RUNTIME); log.error(message.toString()); throw new UserException(message.toString()); } void warn(ClassMetaData meta, Localizer.Message message) { Log log = meta.getRepository().getConfiguration() .getLog(OpenJPAConfiguration.LOG_RUNTIME); log.warn(message.toString()); } void trace(ClassMetaData meta, Localizer.Message message) { Log log = meta.getRepository().getConfiguration() .getLog(OpenJPAConfiguration.LOG_RUNTIME); log.trace(message.toString()); } @Override protected List<String> getFieldAccessNames(ClassMetaData meta) { return toNames(getPersistentFields(meta, false)); } @Override protected List<String> getPropertyAccessNames(ClassMetaData meta) { return toNames(getPersistentMethods(meta, false)); } protected boolean isDefaultPersistent(ClassMetaData meta, Member member, String name) { return isDefaultPersistent(meta, member, name, false); } protected boolean isDefaultPersistent(ClassMetaData meta, Member member, String name, boolean ignoreTransient) { int mods = member.getModifiers(); if (Modifier.isTransient(mods)) return false; int access = meta.getAccessType(); if (member instanceof Field) { // If mixed or unknown, default property access, keep explicit // field members if (AccessCode.isProperty(access)) { if (!isAnnotatedAccess(member, AccessType.FIELD)) return false; } } else if (member instanceof Method) { // If mixed or unknown, field default access, keep explicit property // members if (AccessCode.isField(access)) { if (!isAnnotatedAccess(member, AccessType.PROPERTY)) return false; } try { String setterName; if (member.getName().startsWith("is")) { setterName = "set" + member.getName().substring(2); } else { setterName = "set" + member.getName().substring(3); } // check for setters for methods Method setter = (Method) AccessController.doPrivileged(J2DoPrivHelper.getDeclaredMethodAction( meta.getDescribedType(), setterName, new Class[] { ((Method) member).getReturnType() })); if (setter == null && !isAnnotatedTransient(member)) { logNoSetter(meta, name, null); return false; } } catch (Exception e) { // e.g., NoSuchMethodException if (!isAnnotatedTransient(member)) logNoSetter(meta, name, e); return false; } } PersistenceStrategy strat = getPersistenceStrategy(null, member, ignoreTransient); if (strat == null) { warn(meta, _loc.get("no-pers-strat", meta.getDescribedTypeString() + "." + name)); return false; } else if (strat == PersistenceStrategy.TRANSIENT) { return false; } else { return true; } } private boolean isAnnotatedTransient(Member member) { return member instanceof AnnotatedElement && (AccessController.doPrivileged(J2DoPrivHelper .isAnnotationPresentAction(((AnnotatedElement) member), Transient.class))).booleanValue(); } /** * May be used to determine if member is annotated with the specified * access type. * @param member class member * @param type expected access type * @return true if access is specified on member and that access * type matches the expected type */ private boolean isAnnotatedAccess(Member member, AccessType type) { if (member == null) return false; Access anno = AccessController.doPrivileged(J2DoPrivHelper .getAnnotationAction((AnnotatedElement)member, Access.class)); return anno != null && anno.value() == type; } private boolean isAnnotated(Member member) { return member != null && member instanceof AnnotatedElement && annotatedFilter.includes((AnnotatedElement)member); } private boolean isNotTransient(Member member) { return member != null && member instanceof AnnotatedElement && nonTransientFilter.includes((AnnotatedElement)member); } /** * Gets either the instance field or the getter method depending upon the * access style of the given meta-data. */ public Member getMemberByProperty(ClassMetaData meta, String property, int access, boolean applyDefaultRule) { Class<?> cls = meta.getDescribedType(); Field field = Reflection.findField(cls, property, false);; Method getter = Reflection.findGetter(cls, property, false); Method setter = Reflection.findSetter(cls, property, false); int accessCode = AccessCode.isUnknown(access) ? meta.getAccessType() : access; if (field == null && getter == null) error(meta, _loc.get("access-no-property", cls, property)); if ((isNotTransient(getter) && isAnnotated(getter)) && isNotTransient(field) && isAnnotated(field)) throw new IllegalStateException(_loc.get("access-duplicate", field, getter).toString()); if (AccessCode.isField(accessCode)) { if (isAnnotatedAccess(getter, AccessType.PROPERTY)) { meta.setAccessType(AccessCode.MIXED | meta.getAccessType()); return getter; } return field == null ? getter : field; } else if (AccessCode.isProperty(accessCode)) { if (isAnnotatedAccess(field, AccessType.FIELD)) { meta.setAccessType(AccessCode.MIXED | meta.getAccessType()); return field; } return getter == null ? field : getter; } else if (AccessCode.isUnknown(accessCode)) { if (isAnnotated(field)) { meta.setAccessType(AccessCode.FIELD); return field; } else if (isAnnotated(getter)) { meta.setAccessType(AccessCode.PROPERTY); return getter; } else { warn(meta, _loc.get("access-none", meta, property)); throw new IllegalStateException( _loc.get("access-none", meta, property).toString()); } } else { throw new InternalException(meta + " " + AccessCode.toClassString(meta.getAccessType())); } } // ======================================================================== // Selection Filters select specific elements from a collection. // Used to determine the persistent members of a given class. // ======================================================================== /** * Inclusive element filtering predicate. * */ private static interface InclusiveFilter<T extends AnnotatedElement> { /** * Return true to include the given element. */ boolean includes(T e); } /** * Filter the given collection with the conjunction of filters. The given * collection itself is not modified. */ <T extends AnnotatedElement> List<T> filter(T[] array, InclusiveFilter... filters) { List<T> result = new ArrayList<T>(); for (T e : array) { boolean include = true; for (InclusiveFilter f : filters) { if (f != null && !f.includes(e)) { include = false; break; } } if (include) result.add(e); } return result; } <T extends AnnotatedElement> List<T> filter(List<T> list, InclusiveFilter... filters) { List<T> result = new ArrayList<T>(); for (T e : list) { boolean include = true; for (InclusiveFilter f : filters) { if (f != null && !f.includes(e)) { include = false; break; } } if (include) result.add(e); } return result; } /** * Selects getter method. A getter method name starts with 'get', returns a * non-void type and has no argument. Or starts with 'is', returns a boolean * and has no argument. * */ static class GetterFilter implements InclusiveFilter<Method> { private boolean includePrivate; public boolean includes(Method method) { return isGetter(method, isIncludePrivate()); } public void setIncludePrivate(boolean includePrivate) { this.includePrivate = includePrivate; } public boolean isIncludePrivate() { return includePrivate; } } /** * Selects setter method. A setter method name starts with 'set', returns a * void and has single argument. * */ static class SetterFilter implements InclusiveFilter<Method> { public boolean includes(Method method) { return isSetter(method); } /** * Affirms if the given method matches the following signature * <code> public void setXXX(T t) </code> */ public static boolean isSetter(Method method) { String methodName = method.getName(); return startsWith(methodName, "set") && method.getParameterTypes().length == 1 && method.getReturnType() == void.class; } } /** * Selects elements which is annotated with @Access annotation and that * annotation has the given AccessType value. * */ static class AccessFilter implements InclusiveFilter<AnnotatedElement> { final AccessType target; public AccessFilter(AccessType target) { this.target = target; } public boolean includes(AnnotatedElement obj) { Access access = obj.getAnnotation(Access.class); return access != null && access.value().equals(target); } } /** * Selects elements which is annotated with @Access annotation and that * annotation has the given AccessType value. * */ static class MemberFilter implements InclusiveFilter<AnnotatedElement> { final Class<?> target; public MemberFilter(Class<?> target) { this.target = target; } public boolean includes(AnnotatedElement obj) { int mods = ((Member)obj).getModifiers(); return obj.getClass() == target && !(Modifier.isStatic(mods) || Modifier.isFinal(mods) || Modifier.isTransient(mods) || Modifier.isNative(mods)); } } /** * Selects non-transient elements. Selectively will examine only the * transient field modifier. */ static class TransientFilter implements InclusiveFilter<AnnotatedElement> { final boolean modifierOnly; public TransientFilter(boolean modOnly) { modifierOnly = modOnly; } public boolean includes(AnnotatedElement obj) { if (modifierOnly) { return !Modifier.isTransient(((Member)obj).getModifiers()); } return !obj.isAnnotationPresent(Transient.class) && !Modifier.isTransient(((Member)obj).getModifiers()); } } /** * Selects all element annotated with <code>javax.persistence.*</code> or * <code>org.apache.openjpa.*</code> annotation except the annotations * marked to be ignored. */ static class AnnotatedFilter implements InclusiveFilter<AnnotatedElement> { public boolean includes(AnnotatedElement obj) { Annotation[] annos = AccessController.doPrivileged(J2DoPrivHelper .getAnnotationsAction(obj)); for (Annotation anno : annos) { String name = anno.annotationType().getName(); if ((name.startsWith("javax.persistence.") || name.startsWith("org.apache.openjpa.persistence.")) && !_ignoredAnnos.contains(name)) return true; } return false; } } private void logNoSetter(ClassMetaData meta, String name, Exception e) { Log log = meta.getRepository().getConfiguration() .getLog(OpenJPAConfiguration.LOG_METADATA); if (log.isWarnEnabled()) log.warn(_loc.get("no-setter-for-getter", name, meta.getDescribedType().getName())); else if (log.isTraceEnabled()) // log the exception, if any, if we're in trace-level debugging log.warn(_loc.get("no-setter-for-getter", name, meta.getDescribedType().getName()), e); } private Log getLog(ClassMetaData meta) { return meta.getRepository().getConfiguration() .getLog(OpenJPAConfiguration.LOG_METADATA); } String toFieldNames(List<Field> fields) { return fields.toString(); } String toMethodNames(List<Method> methods) { return methods.toString(); } public boolean isAbstractMappingUniDirectional(OpenJPAConfiguration conf) { if (_isAbstractMappingUniDirectional == null) setAbstractMappingUniDirectional(conf); return _isAbstractMappingUniDirectional; } public void setAbstractMappingUniDirectional(OpenJPAConfiguration conf) { _isAbstractMappingUniDirectional = conf.getCompatibilityInstance().isAbstractMappingUniDirectional(); } public boolean isNonDefaultMappingAllowed(OpenJPAConfiguration conf) { if (_isNonDefaultMappingAllowed == null) setNonDefaultMappingAllowed(conf); return _isNonDefaultMappingAllowed; } public void setNonDefaultMappingAllowed(OpenJPAConfiguration conf) { _isNonDefaultMappingAllowed = conf.getCompatibilityInstance(). isNonDefaultMappingAllowed(); } public Boolean isDefaultCascadePersistEnabled() { return _isCascadePersistPersistenceUnitDefaultEnabled; } public void setDefaultCascadePersistEnabled(Boolean bool) { _isCascadePersistPersistenceUnitDefaultEnabled = bool; } @Override public String getDefaultSchema() { return _defaultSchema; } @Override public void setDefaultSchema(String schema) { _defaultSchema=schema; } }