package org.wamblee.persistence;
import java.io.Serializable;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import javax.persistence.Id;
import javax.persistence.Version;
-import org.wamblee.reflection.ReflectionUtils;
+import org.wamblee.reflection.Accessor;
+import org.wamblee.reflection.AnnotationUtils;
/**
- * Factory which creates a {@link Persistent} object for a given entity for
+ * Factory which creates a {@link Persistent} object for a given JPA entity for
* interfacing with the primary key and version of the entity.
*
* This utility only treats primary keys and fields that are annotated with @Id
*/
private static Map<String, EntityAccessor> CACHE = new ConcurrentHashMap<String, EntityAccessor>();
- static interface Accessor<T> {
- void set(Object aEntity, T aValue);
-
- T get(Object aEntity);
- }
-
- static class FieldAccessor<T> implements Accessor<T> {
- private Field field;
-
- public FieldAccessor(Field aField) {
- field = aField;
- field.setAccessible(true);
- }
-
- @Override
- public T get(Object aEntity) {
- try {
- return (T) field.get(aEntity);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void set(Object aEntity, T aValue) {
- try {
- field.set(aEntity, aValue);
- } catch (IllegalAccessException e) {
- throw new RuntimeException(e.getMessage(), e);
- }
- }
-
- public Field getField() {
- return field;
- }
- }
-
- static class PropertyAccessor<T> implements Accessor<T> {
- private Method getter;
- private Method setter;
-
- public PropertyAccessor(Method aGetter, Method aSetter) {
- getter = aGetter;
- setter = aSetter;
- getter.setAccessible(true);
- setter.setAccessible(true);
- }
-
- @Override
- public T get(Object aEntity) {
- try {
- return (T) getter.invoke(aEntity);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- @Override
- public void set(Object aEntity, T aValue) {
- try {
- setter.invoke(aEntity, aValue);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
-
- public Method getGetter() {
- return getter;
- }
-
- public Method getSetter() {
- return setter;
- }
- }
-
static class EntityAccessor {
private Accessor pk;
private Accessor version;
@Override
public Serializable getPrimaryKey() {
- return (Serializable)accessor.getPk().get(entity);
+ if (accessor == null || accessor.getPk() == null) {
+ return null;
+ }
+ return (Serializable) accessor.getPk().get(entity);
}
@Override
public void setPrimaryKey(Serializable aKey) {
+ if (accessor == null || accessor.getPk() == null) {
+ return;
+ }
accessor.getPk().set(entity, aKey);
- }
+ }
@Override
public Number getPersistedVersion() {
- return (Number)accessor.getVersion().get(entity);
+ if (accessor == null || accessor.getVersion() == null) {
+ return null;
+ }
+ return (Number) accessor.getVersion().get(entity);
}
@Override
public void setPersistedVersion(Number aVersion) {
+ if (accessor == null || accessor.getVersion() == null) {
+ return;
+ }
accessor.getVersion().set(entity, aVersion);
}
}
}
private static EntityAccessor analyse(Class aClass) {
- Accessor<Serializable> pk = analyse(aClass, Id.class);
- Accessor<Integer> version = analyse(aClass, Version.class);
+ List<Accessor> pkAccessors = AnnotationUtils.analyse(aClass, Id.class);
+ List<Accessor> versionAccessors = AnnotationUtils.analyse(aClass,
+ Version.class);
+ Accessor<Serializable> pk = null;
+ if (pkAccessors.size() > 0) {
+ pk = pkAccessors.get(0);
+ }
+ Accessor<Integer> version = null;
+ if (versionAccessors.size() > 0) {
+ version = versionAccessors.get(0);
+ }
if (pk != null || version != null) {
return new EntityAccessor(pk, version);
}
}
/**
- * Returns the accessor for a given annotation.
+ * Creates the {@link Persistent} wrapper for interfacing with primary key
+ * and version of the entity.
*
- * @param aClass
- * Class to analyse.
- * @param aAnnotation
- * Annotation that must be present.
- * @return Accessor to use or null if the annotation is not present.
- */
- private static Accessor analyse(Class aClass,
- Class<? extends Annotation> aAnnotation) {
- List<Field> fields = ReflectionUtils.getAllFields(aClass);
- for (Field field : fields) {
- if (field.isAnnotationPresent(aAnnotation)) {
- return new FieldAccessor(field);
- }
- }
- List<Method> methods = ReflectionUtils.getAllMethods(aClass,
- Object.class);
- for (Method method : methods) {
- if (method.isAnnotationPresent(aAnnotation)) {
- String setterName = null;
- if (method.getName().startsWith("get")) {
- setterName = method.getName().replaceFirst("get", "set");
- } else if (method.getName().startsWith("is")) {
- setterName = method.getName().replaceFirst("is", "set");
- }
- try {
- Class returnType = method.getReturnType();
- Method setter = method.getDeclaringClass().getDeclaredMethod(setterName, returnType);
- return new PropertyAccessor(method, setter);
- } catch (NoSuchMethodException e) {
- throw new RuntimeException("Error obtaining setter for " +
- method.getName() + " in class " + aClass.getName(), e);
- }
- }
- }
- return null;
- }
-
- /**
- * Creates the {@link Persistent} wrapper for interfacing with primary key and
- * version of the entity.
- * @param aEntity Entity to use.
- * @return Persistent object or null if this is not an entity.
+ * @param aEntity
+ * Entity to use.
+ * @return Persistent object or null if this is not an entity.
*/
- public static Persistent create(Object aEntity) {
+ public static Persistent create(Object aEntity) {
EntityAccessor accessor = createEntityAccessor(aEntity.getClass());
- if ( accessor == null ) {
- return null;
+ if (accessor == null) {
+ return null;
}
return new EntityObjectAccessor(aEntity, accessor);
}