// Copyright (c) 2003-present, Jodd Team (http://jodd.org) // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // 1. Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // 2. Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE // POSSIBILITY OF SUCH DAMAGE. package jodd.introspector; /** * Property descriptor. It consist of read, write and field descriptor. * Only one of those three descriptors may exist. */ public class PropertyDescriptor extends Descriptor { protected final String name; protected final MethodDescriptor readMethodDescriptor; protected final MethodDescriptor writeMethodDescriptor; protected final FieldDescriptor fieldDescriptor; /** * Creates field-only property descriptor. */ public PropertyDescriptor(ClassDescriptor classDescriptor, String propertyName, FieldDescriptor fieldDescriptor) { super(classDescriptor, false); this.name = propertyName; this.readMethodDescriptor = null; this.writeMethodDescriptor = null; this.fieldDescriptor = fieldDescriptor; } /** * Creates property descriptor. */ public PropertyDescriptor(ClassDescriptor classDescriptor, String propertyName, MethodDescriptor readMethod, MethodDescriptor writeMethod) { super(classDescriptor, ((readMethod == null) || readMethod.isPublic()) & (writeMethod == null || writeMethod.isPublic()) ); this.name = propertyName; this.readMethodDescriptor = readMethod; this.writeMethodDescriptor = writeMethod; if (classDescriptor.isExtendedProperties()) { String[] prefix = classDescriptor.getPropertyFieldPrefix(); FieldDescriptor fd = null; if (prefix != null) { for (String p : prefix) { fd = findField(p + propertyName); if (fd != null) { break; } } } else { fd = findField(propertyName); } this.fieldDescriptor = fd; } else { this.fieldDescriptor = null; } } /** * Locates property field. Field is being searched also in all * superclasses of current class. */ protected FieldDescriptor findField(String fieldName) { FieldDescriptor fieldDescriptor = classDescriptor.getFieldDescriptor(fieldName, true); if (fieldDescriptor != null) { return fieldDescriptor; } // field descriptor not found in this class // try to locate it in the superclasses Class[] superclasses = classDescriptor.getAllSuperclasses(); for (Class superclass : superclasses) { ClassDescriptor classDescriptor = ClassIntrospector.lookup(superclass); fieldDescriptor = classDescriptor.getFieldDescriptor(fieldName, true); if (fieldDescriptor != null) { return fieldDescriptor; } } // nothing found return null; } /** * Returns property name. */ public String getName() { return name; } /** * Returns read method of this property. * May be <code>null</code> if read method is not defined. */ public MethodDescriptor getReadMethodDescriptor() { return readMethodDescriptor; } /** * Returns write method of this property. * May be <code>null</code> for read-only properties. */ public MethodDescriptor getWriteMethodDescriptor() { return writeMethodDescriptor; } /** * Returns the associated field of this property. * May be <code>null</code> if properties are not enhanced by field description. */ public FieldDescriptor getFieldDescriptor() { return fieldDescriptor; } /** * Returns <code>true</code> if this is an extended property with * only field definition and without getter and setter. */ public boolean isFieldOnly() { return (readMethodDescriptor == null) && (writeMethodDescriptor == null); } /** * Returns <code>true</code> if this property has only a getter method. */ public boolean isGetterOnly() { return (fieldDescriptor == null) && (writeMethodDescriptor == null); } /** * Returns <code>true</code> if this property has only a setter method. */ public boolean isSetterOnly() { return (fieldDescriptor == null) && (readMethodDescriptor == null); } // ---------------------------------------------------------------- type protected Class type; /** * Returns property type. Raw types are detected. */ public Class getType() { if (type == null) { if (fieldDescriptor != null) { type = fieldDescriptor.getRawType(); } else if (readMethodDescriptor != null) { type = readMethodDescriptor.getGetterRawType(); } else if (writeMethodDescriptor != null) { type = writeMethodDescriptor.getSetterRawType(); } } return type; } // ---------------------------------------------------------------- getters & setters protected Getter[] getters; protected Setter[] setters; /** * Returns {@link Getter}. May return <code>null</code> * if no matched getter is found. */ public Getter getGetter(boolean declared) { if (getters == null) { getters = new Getter[] { createGetter(false), createGetter(true), }; } return getters[declared ? 1 : 0]; } /** * Creates a {@link Getter}. */ protected Getter createGetter(boolean declared) { if (readMethodDescriptor != null) { if (readMethodDescriptor.matchDeclared(declared)) { return readMethodDescriptor; } } if (fieldDescriptor != null) { if (fieldDescriptor.matchDeclared(declared)) { return fieldDescriptor; } } return null; } /** * Returns {@link Setter}. May return <code>null</code> * if no matched setter is found. */ public Setter getSetter(boolean declared) { if (setters == null) { setters = new Setter[] { createSetter(false), createSetter(true), }; } return setters[declared ? 1 : 0]; } /** * Creates a {@link Setter}. */ protected Setter createSetter(boolean declared) { if (writeMethodDescriptor != null) { if (writeMethodDescriptor.matchDeclared(declared)) { return writeMethodDescriptor; } } if (fieldDescriptor != null) { if (fieldDescriptor.matchDeclared(declared)) { return fieldDescriptor; } } return null; } // ---------------------------------------------------------------- resolvers /** * Resolves key type for given property descriptor. */ public Class resolveKeyType(boolean declared) { Class keyType = null; Getter getter = getGetter(declared); if (getter != null) { keyType = getter.getGetterRawKeyComponentType(); } if (keyType == null) { FieldDescriptor fieldDescriptor = getFieldDescriptor(); if (fieldDescriptor != null) { keyType = fieldDescriptor.getRawKeyComponentType(); } } return keyType; } /** * Resolves component type for given property descriptor. */ public Class resolveComponentType(boolean declared) { Class componentType = null; Getter getter = getGetter(declared); if (getter != null) { componentType = getter.getGetterRawComponentType(); } if (componentType == null) { FieldDescriptor fieldDescriptor = getFieldDescriptor(); if (fieldDescriptor != null) { componentType = fieldDescriptor.getRawComponentType(); } } return componentType; } }