/* * Copyright 2013 Chris Pheby * * Licensed 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.jadira.reflection.access.model; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.concurrent.ConcurrentHashMap; import org.jadira.reflection.access.api.FieldAccess; import org.jadira.reflection.cloning.annotation.Transient; /** * Provides a model resulting from introspection of a field of a class suitable for use with Java Reflection */ public class FieldModel<C> { private static final ConcurrentHashMap<String, FieldModel<?>> fieldModels = new ConcurrentHashMap<String, FieldModel<?>>(100); private static final Object MONITOR = new Object(); private final FieldAccess<C> fieldAccess; private final Field field; private final FieldType fieldType; private final Class<?> fieldClass; private final boolean transientField; private final boolean transientAnnotatedField; private final boolean isSynthetic; private final boolean isPrivate; private FieldModel(Field field, FieldAccess<C> fieldAccess) { this.fieldAccess = fieldAccess; this.isPrivate = Modifier.isPrivate(field.getModifiers()); this.field = field; if (field.getType().isPrimitive()) { this.fieldType = FieldType.PRIMITIVE; } else if (field.getType().isArray()) { this.fieldType = FieldType.ARRAY; } else { this.fieldType = FieldType.OBJECT; } this.fieldClass = field.getType(); this.transientField = Modifier.isTransient(field.getModifiers()); this.transientAnnotatedField = field.getAnnotation(Transient.class) != null; this.isSynthetic = field.isSynthetic(); } /** * Returns a field model for the given Field and FieldAccess instance. If a FieldModel * already exists, it will be reused. * @param f The Field * @param fieldAccess The Field Access that can be used to introspect the field * @param <C> The type of class being accessed * @return The Field Model */ @SuppressWarnings("unchecked") public static final <C> FieldModel<C> get(Field f, FieldAccess<C> fieldAccess) { String fieldModelKey = (fieldAccess.getClass().getSimpleName() + ":" + f.getClass().getName() + "#" + f.getName()); FieldModel<C> fieldModel = (FieldModel<C>)fieldModels.get(fieldModelKey); if (fieldModel != null) { return fieldModel; } synchronized(MONITOR) { fieldModel = (FieldModel<C>)fieldModels.get(fieldModelKey); if (fieldModel != null) { return fieldModel; } else { fieldModel = new FieldModel<C>(f, fieldAccess); fieldModels.putIfAbsent(fieldModelKey, fieldModel); return fieldModel; } } } /** * Access the FieldAccess associated with the FieldModel * @return The associated FieldAccess. */ public FieldAccess<C> getFieldAccess() { return fieldAccess; } /** * Access the Field associated with the FieldModel * @return The associated Field */ public Field getField() { return field; } /** * Indicates the type of the Field - Primitive, Array or Object * @return The FieldType */ public FieldType getFieldType() { return fieldType; } /** * Gets the Declared Class for the Field * @return The Class for the Field */ public Class<?> getFieldClass() { return fieldClass; } /** * Indicates whether the field is transient * @return True if transient */ public boolean isTransientField() { return transientField; } /** * Indicates whether the field carries a Transient annotation * @return True if transient annotated */ public boolean isTransientAnnotatedField() { return transientAnnotatedField; } /** * Indicates whether the field is synthetic according to the Java Language Specific * @return True if synthetic */ public boolean isSynthetic() { return isSynthetic; } /** * Indicates whether the field is private access * @return True if private */ public boolean isPrivate() { return isPrivate; } }