| /** |
| * Copyright 2009-2013 Oy Vaadin Ltd |
| * |
| * 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.eclipse.osbp.dsl.dto.lib.services.jpa.metadata; |
| |
| import java.io.InvalidObjectException; |
| import java.io.ObjectStreamException; |
| import java.lang.annotation.Annotation; |
| import java.lang.reflect.Field; |
| import java.lang.reflect.Method; |
| |
| /** |
| * An extended version of {@link PropertyMetadata} that provides additional |
| * information about persistent properties. |
| * |
| * @author Petter Holmström (Vaadin Ltd) |
| * @since 1.0 |
| */ |
| public class PersistentPropertyMetadata extends PropertyMetadata { |
| |
| private static final long serialVersionUID = -4097189601179456814L; |
| |
| /** |
| * Enumeration defining the property access types. |
| * |
| * @author Petter Holmström (Vaadin Ltd) |
| */ |
| public enum AccessType { |
| |
| /** |
| * The property is accessed as a JavaBean property using getters and |
| * setters. |
| */ |
| METHOD, |
| /** |
| * The property is accessed directly as a field. |
| */ |
| FIELD |
| } |
| |
| private final PropertyKind propertyKind; |
| private final ClassMetadata<?> typeMetadata; |
| transient final Field field; |
| // Required for serialization |
| protected final String fieldName; |
| protected final Class<?> fieldDeclaringClass; |
| |
| /** |
| * Creates a new instance of <code>PersistentPropertyMetadata</code>. |
| * |
| * @param name |
| * the name of the property (must not be null). |
| * @param type |
| * the type of the property (must not be null). |
| * @param propertyKind |
| * the kind of the property, must be either |
| * {@link PropertyKind#ONE_TO_MANY}, |
| * {@link PropertyKind#MANY_TO_MANY}, |
| * {@link PropertyKind#ELEMENT_COLLECTION} or |
| * {@link PropertyKind#SIMPLE} . |
| * @param field |
| * the field that can be used to access the property (must not be |
| * null). |
| */ |
| PersistentPropertyMetadata(String name, Class<?> type, |
| PropertyKind propertyKind, Field field, Method setter) { |
| super(name, type, null, setter); |
| assert propertyKind == PropertyKind.ONE_TO_MANY |
| || propertyKind == PropertyKind.MANY_TO_MANY |
| || propertyKind == PropertyKind.ELEMENT_COLLECTION |
| || propertyKind == PropertyKind.SIMPLE : "propertyKind must be ONE_TO_MANY or SIMPLE"; |
| assert field != null : "field must not be null"; |
| this.propertyKind = propertyKind; |
| typeMetadata = null; |
| this.field = field; |
| fieldName = field.getName(); |
| fieldDeclaringClass = field.getDeclaringClass(); |
| } |
| |
| /** |
| * Creates a new instance of <code>PersistentPropertyMetadata</code>. |
| * |
| * @param name |
| * the name of the property (must not be null). |
| * @param type |
| * type type of the property (must not be null). |
| * @param propertyKind |
| * the kind of the property, must be either |
| * {@link PropertyKind#ONE_TO_MANY}, |
| * {@link PropertyKind#MANY_TO_MANY}, |
| * {@link PropertyKind#ELEMENT_COLLECTION} or |
| * {@link PropertyKind#SIMPLE} . |
| * @param getter |
| * the getter method that can be used to read the property value |
| * (must not be null). |
| * @param setter |
| * the setter method that can be used to set the property value |
| * (must not be null). |
| */ |
| PersistentPropertyMetadata(String name, Class<?> type, |
| PropertyKind propertyKind, Method getter, Method setter) { |
| super(name, type, getter, setter); |
| assert propertyKind == PropertyKind.ONE_TO_MANY |
| || propertyKind == PropertyKind.MANY_TO_MANY |
| || propertyKind == PropertyKind.ELEMENT_COLLECTION |
| || propertyKind == PropertyKind.SIMPLE : "propertyKind must be ONE_TO_MANY or SIMPLE"; |
| assert getter != null : "getter must not be null"; |
| assert setter != null : "setter must not be null"; |
| this.propertyKind = propertyKind; |
| typeMetadata = null; |
| field = null; |
| fieldName = null; |
| fieldDeclaringClass = null; |
| } |
| |
| /** |
| * Creates a new instance of <code>PersistentPropertyMetadata</code>. |
| * |
| * @param name |
| * the name of the property (must not be null). |
| * @param type |
| * the type metadata of the property (must not be null). |
| * @param propertyKind |
| * the kind of the property, must be either |
| * {@link PropertyKind#MANY_TO_ONE}, |
| * {@link PropertyKind#ONE_TO_ONE} or |
| * {@link PropertyKind#EMBEDDED}. |
| * @param field |
| * the field that can be used to access the property (must not be |
| * null). |
| */ |
| PersistentPropertyMetadata(String name, ClassMetadata<?> type, |
| PropertyKind propertyKind, Field field, Method setter) { |
| super(name, type.getMappedClass(), null, setter); |
| assert type != null : "type must not be null"; |
| assert propertyKind == PropertyKind.MANY_TO_ONE |
| || propertyKind == PropertyKind.ONE_TO_ONE |
| || propertyKind == PropertyKind.EMBEDDED : "propertyKind must be MANY_TO_ONE or EMBEDDED"; |
| assert field != null : "field must not be null"; |
| this.propertyKind = propertyKind; |
| typeMetadata = type; |
| this.field = field; |
| fieldName = field.getName(); |
| fieldDeclaringClass = field.getDeclaringClass(); |
| } |
| |
| /** |
| * Creates a new instance of <code>PersistentPropertyMetadata</code>. |
| * |
| * @param name |
| * the name of the property (must not be null). |
| * @param type |
| * the type metadata of the property (must not be null). |
| * @param propertyKind |
| * the kind of the property, must be either |
| * {@link PropertyKind#MANY_TO_ONE}, |
| * {@link PropertyKind#ONE_TO_ONE} or |
| * {@link PropertyKind#EMBEDDED}. |
| * @param getter |
| * the getter method that can be used to read the property value |
| * (must not be null). |
| * @param setter |
| * the setter method that can be used to set the property value |
| * (must not be null). |
| */ |
| PersistentPropertyMetadata(String name, ClassMetadata<?> type, |
| PropertyKind propertyKind, Method getter, Method setter) { |
| super(name, type.getMappedClass(), getter, setter); |
| assert type != null : "type must not be null"; |
| assert propertyKind == PropertyKind.MANY_TO_ONE |
| || propertyKind == PropertyKind.ONE_TO_ONE |
| || propertyKind == PropertyKind.EMBEDDED : "propertyKind must be MANY_TO_ONE or EMBEDDED"; |
| assert getter != null : "getter must not be null"; |
| assert setter != null : "setter must not be null"; |
| this.propertyKind = propertyKind; |
| typeMetadata = type; |
| field = null; |
| fieldName = null; |
| fieldDeclaringClass = null; |
| } |
| |
| /** |
| * This constructor is used when deserializing the object. |
| * |
| * @see #readResolve() |
| */ |
| private PersistentPropertyMetadata(String name, |
| ClassMetadata<?> typeMetadata, Class<?> type, |
| PropertyKind propertyKind, Method getter, Method setter, Field field) { |
| super(name, type, getter, setter); |
| this.propertyKind = propertyKind; |
| this.typeMetadata = typeMetadata; |
| this.field = field; |
| if (this.field == null) { |
| fieldName = null; |
| fieldDeclaringClass = null; |
| } else { |
| fieldName = field.getName(); |
| fieldDeclaringClass = field.getDeclaringClass(); |
| } |
| } |
| |
| /** |
| * The metadata of the property type, if it is embedded or a reference. |
| * Otherwise, this method returns null. |
| * |
| * @see #getPropertyKind() |
| */ |
| public ClassMetadata<?> getTypeMetadata() { |
| return typeMetadata; |
| } |
| |
| /** |
| * The kind of the property. |
| */ |
| @Override |
| public PropertyKind getPropertyKind() { |
| return propertyKind; |
| } |
| |
| /** |
| * The way the property value is accessed (as a JavaBean property or as a |
| * field). |
| */ |
| public AccessType getAccessType() { |
| return field != null ? AccessType.FIELD : AccessType.METHOD; |
| } |
| |
| @Override |
| public <T extends Annotation> T getAnnotation(Class<T> annotationClass) { |
| if (field != null) { |
| return field.getAnnotation(annotationClass); |
| } else { |
| return super.getAnnotation(annotationClass); |
| } |
| } |
| |
| @Override |
| public Annotation[] getAnnotations() { |
| if (field != null) { |
| return field.getAnnotations(); |
| } else { |
| return super.getAnnotations(); |
| } |
| } |
| |
| @Override |
| public Object readResolve() throws ObjectStreamException { |
| try { |
| Field f = null; |
| if (fieldName != null) { |
| f = fieldDeclaringClass.getDeclaredField(fieldName); |
| } |
| Method getterM = null; |
| if (getterName != null) { |
| getterM = getterDeclaringClass.getDeclaredMethod(getterName); |
| } |
| Method setterM = null; |
| if (setterName != null) { |
| // use the type from field if possible. type is Vaadin property |
| // type, which means that for primitive types we convert it to |
| // wrapper type |
| Class<?> setterType = (f == null) ? getType() : f.getType(); |
| setterM = setterDeclaringClass.getDeclaredMethod(setterName, |
| setterType); |
| } |
| return new PersistentPropertyMetadata(getName(), typeMetadata, |
| getType(), propertyKind, getterM, setterM, f); |
| } catch (Exception e) { |
| e.printStackTrace(); |
| throw new InvalidObjectException(e.getMessage()); |
| } |
| } |
| |
| /** |
| * Persistent properties are always writable. |
| * <p> |
| * {@inheritDoc }. |
| */ |
| @Override |
| public boolean isWritable() { |
| return true; // field != null || super.isWritable(); |
| } |
| |
| /* |
| * Note, that we only compare the mapped classes of the typeMetadata fields. |
| * If we compared the typeMetadata fields themselves, we could run into an |
| * infinite loop if there are circular references (e.g. a parent-property of |
| * the same type) in the metadata. |
| */ |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (super.equals(obj)) { // Includes check of parameter type |
| PersistentPropertyMetadata other = (PersistentPropertyMetadata) obj; |
| return ( other != null && propertyKind.equals(other.propertyKind) ) |
| && (typeMetadata == null ? other.typeMetadata == null |
| : typeMetadata.getMappedClass().equals( |
| other.typeMetadata.getMappedClass())) |
| && (field == null ? other.field == null : field |
| .equals(other.field)); |
| } |
| return false; |
| } |
| |
| @Override |
| public int hashCode() { |
| int hash = super.hashCode(); |
| hash = hash * 31 + propertyKind.hashCode(); |
| if (typeMetadata != null) { |
| hash = hash * 31 + typeMetadata.getMappedClass().hashCode(); |
| } |
| if (field != null) { |
| hash = hash * 31 + field.hashCode(); |
| } |
| return hash; |
| } |
| } |