| /******************************************************************************* |
| * Copyright (c) 2012 Oracle. All rights reserved. |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License v1.0, which accompanies this distribution |
| * and is available at http://www.eclipse.org/legal/epl-v10.html. |
| * |
| * Contributors: |
| * Oracle - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.jpt.jpa.eclipselink.core.internal.context.orm; |
| |
| import org.eclipse.jdt.core.IType; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.dom.CompilationUnit; |
| import org.eclipse.jpt.common.core.internal.utility.JDTTools; |
| import org.eclipse.jpt.common.core.resource.java.JavaResourceAttribute; |
| import org.eclipse.jpt.common.core.resource.java.JavaResourceField; |
| import org.eclipse.jpt.common.core.resource.java.JavaResourceMethod; |
| import org.eclipse.jpt.common.core.utility.TextRange; |
| import org.eclipse.jpt.common.utility.internal.ClassName; |
| import org.eclipse.jpt.common.utility.internal.iterables.ArrayIterable; |
| import org.eclipse.jpt.jpa.core.JpaStructureNode; |
| import org.eclipse.jpt.jpa.core.context.AccessType; |
| import org.eclipse.jpt.jpa.core.context.CollectionMapping; |
| import org.eclipse.jpt.jpa.core.context.TypeMapping; |
| import org.eclipse.jpt.jpa.core.context.java.Accessor; |
| import org.eclipse.jpt.jpa.core.context.java.JavaAttributeMapping; |
| import org.eclipse.jpt.jpa.core.context.java.JavaPersistentAttribute; |
| import org.eclipse.jpt.jpa.core.context.orm.EntityMappings; |
| import org.eclipse.jpt.jpa.core.context.orm.OrmPersistentType; |
| import org.eclipse.jpt.jpa.core.internal.context.java.AbstractJavaJpaContextNode; |
| import org.eclipse.jpt.jpa.core.internal.jpa1.context.java.GenericJavaNullAttributeMapping; |
| import org.eclipse.jpt.jpa.core.jpa2.context.MetamodelField; |
| import org.eclipse.jpt.jpa.core.jpa2.context.java.JavaPersistentAttribute2_0; |
| import org.eclipse.jpt.jpa.core.jpa2.resource.java.JPA2_0; |
| import org.eclipse.jpt.jpa.eclipselink.core.JptJpaEclipseLinkCorePlugin; |
| import org.eclipse.jpt.jpa.eclipselink.core.context.java.JavaEclipseLinkPersistentAttribute; |
| import org.eclipse.jpt.jpa.eclipselink.core.resource.orm.XmlAttributeMapping; |
| |
| public class VirtualJavaPersistentAttribute extends AbstractJavaJpaContextNode |
| implements JavaPersistentAttribute2_0, JavaEclipseLinkPersistentAttribute |
| { |
| private final XmlAttributeMapping xmlAttributeMapping; |
| |
| private final JavaAttributeMapping attributeMapping; |
| |
| public VirtualJavaPersistentAttribute(OrmPersistentType parent, XmlAttributeMapping xmlAttributeMapping) { |
| super(parent); |
| this.xmlAttributeMapping = xmlAttributeMapping; |
| this.attributeMapping = new GenericJavaNullAttributeMapping(this); |
| } |
| |
| public XmlAttributeMapping getXmlAttributeMapping() { |
| return this.xmlAttributeMapping; |
| } |
| |
| public JavaAttributeMapping getMapping() { |
| return this.attributeMapping; |
| } |
| |
| public JavaAttributeMapping setMappingKey(String key) { |
| throw new UnsupportedOperationException("cannot set anything on a virtual java persistent attribute"); //$NON-NLS-1$ |
| } |
| |
| public Accessor getAccessor() { |
| return null; |
| } |
| |
| public JavaResourceAttribute getResourceAttribute() { |
| return null; |
| } |
| |
| public boolean isFor(JavaResourceField resourceField) { |
| return false; |
| } |
| |
| public boolean isFor(JavaResourceMethod resourceGetter, JavaResourceMethod resourceSetter) { |
| return false; |
| } |
| |
| public boolean contains(int offset, CompilationUnit astRoot) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public String getTypeName() { |
| String typeName = this.xmlAttributeMapping.getAttributeType(); |
| return typeName == null ? null : this.getEntityMappings().getFullyQualifiedName(typeName); |
| } |
| |
| public boolean typeIsBasic() { |
| return false;//not valid for a default basic mapping, specified in orm.xml |
| } |
| |
| public String getSingleReferenceTargetTypeName() { |
| return null; //used for building default target entity/embeddable, must be specified in a virtual mapping |
| } |
| |
| public String getMultiReferenceTargetTypeName() { |
| return null; //used for building default target entity/target class, must be specified in a virtual mapping |
| } |
| |
| public String getMultiReferenceMapKeyTypeName() { |
| return null; //used for building default map key class, must be specified in a virtual mapping |
| } |
| |
| public String getName() { |
| return this.xmlAttributeMapping.getName(); |
| } |
| |
| public String getMappingKey() { |
| return null; |
| } |
| |
| public String getDefaultMappingKey() { |
| return null; |
| } |
| |
| public boolean isVirtual() { |
| throw new UnsupportedOperationException("Owing orm persistent attribute is specified, this should not be called."); //$NON-NLS-1$ |
| } |
| |
| public JavaPersistentAttribute getJavaPersistentAttribute() { |
| return this; |
| } |
| |
| |
| // ********** JpaStructureNode implementation ********** |
| |
| |
| public JpaStructureNode getStructureNode(int textOffset) { |
| throw new UnsupportedOperationException("There is no resource for a virtual java persistent attribute"); //$NON-NLS-1$ |
| } |
| |
| public TextRange getSelectionTextRange() { |
| throw new UnsupportedOperationException("There is no resource for a virtual java persistent attribute"); //$NON-NLS-1$ |
| } |
| |
| public ContextType getContextType() { |
| throw new UnsupportedOperationException("There is no resource for a virtual java persistent attribute"); //$NON-NLS-1$ |
| } |
| |
| public Class<? extends JpaStructureNode> getType() { |
| throw new UnsupportedOperationException("There is no resource for a virtual java persistent attribute"); //$NON-NLS-1$ |
| } |
| |
| public void dispose() { |
| throw new UnsupportedOperationException("There is no resource for a virtual java persistent attribute"); //$NON-NLS-1$ |
| } |
| |
| public AccessType getAccess() { |
| return null; |
| } |
| |
| public AccessType getSpecifiedAccess() { |
| return null; |
| } |
| |
| public void setSpecifiedAccess(AccessType newSpecifiedAccess) { |
| throw new UnsupportedOperationException("cannot set anything on a virtual java persistent attribute"); //$NON-NLS-1$ |
| } |
| |
| public AccessType getDefaultAccess() { |
| return null; |
| } |
| |
| public TextRange getValidationTextRange(CompilationUnit astRoot) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| |
| public boolean typeIsDateOrCalendar() { |
| String typeName = this.getTypeName(); |
| if (typeName == null) { |
| return false; |
| } |
| return JDTTools.typeIsSubType(this.getJavaProject(), typeName, DATE_TYPE_NAME) |
| || JDTTools.typeIsSubType(this.getJavaProject(), typeName, CALENDAR_TYPE_NAME); |
| } |
| |
| public boolean typeIsSerializable() { |
| String typeName = this.getTypeName(); |
| if (typeName == null) { |
| return false; |
| } |
| return JDTTools.typeIsSubType(this.getJavaProject(), typeName, JDTTools.SERIALIZABLE_CLASS_NAME); |
| } |
| |
| public boolean typeIsValidForVariableOneToOne() { |
| String typeName = this.getTypeName(); |
| if (typeName == null) { |
| return false; |
| } |
| IType type = JDTTools.findType(getJavaProject(), typeName); |
| try { |
| return type != null && |
| type.isInterface() && |
| this.interfaceIsValidForVariableOneToOne(typeName); |
| } |
| catch (JavaModelException e) { |
| JptJpaEclipseLinkCorePlugin.log(e); |
| return false; |
| } |
| } |
| |
| protected boolean interfaceIsValidForVariableOneToOne(String interfaceName) { |
| return ! this.interfaceIsInvalidForVariableOneToOne(interfaceName); |
| } |
| |
| // TODO we could probably add more interfaces to this list... |
| protected boolean interfaceIsInvalidForVariableOneToOne(String interfaceName) { |
| return (interfaceName == null) || |
| this.typeIsContainer(interfaceName) || |
| interfaceName.equals("org.eclipse.persistence.indirection.ValueHolderInterface"); //$NON-NLS-1$ |
| } |
| |
| /** |
| * return whether the specified type is one of the container |
| * types allowed by the JPA spec |
| */ |
| protected boolean typeIsContainer(String typeName) { |
| return this.getJpaContainerDefinition(typeName).isContainer(); |
| } |
| |
| |
| // ********** metamodel ********** |
| |
| public String getMetamodelContainerFieldTypeName() { |
| throw new UnsupportedOperationException("parent OrmPersistentAttribute implements this"); //$NON-NLS-1$ |
| } |
| |
| public String getMetamodelContainerFieldMapKeyTypeName() { |
| throw new UnsupportedOperationException("parent OrmPersistentAttribute implements this"); //$NON-NLS-1$ |
| } |
| |
| |
| public String getMetamodelTypeName() { |
| String typeName = this.getTypeName(); |
| if (typeName == null) { |
| return MetamodelField.DEFAULT_TYPE_NAME; |
| } |
| if (ClassName.isPrimitive(typeName)) { |
| return ClassName.getWrapperClassName(typeName); // ??? |
| } |
| return typeName; |
| } |
| |
| public JpaContainerDefinition getJpaContainerDefinition() { |
| // 'typeName' may include array brackets ("[]") |
| // but not generic type arguments (e.g. "<java.lang.String>") |
| return this.getJpaContainerDefinition(this.getTypeName()); |
| } |
| |
| //I don't think we should be doing this here, I think OrmAttributeMappings should be responsible for their own JpaContainerDefinition |
| //Generic can just get it from the JavaPersistentAttribute |
| /** |
| * Return the JPA container definition corresponding to the specified type; |
| * return a "null" definition if the specified type is not "assignable to" one of the |
| * container types allowed by the JPA spec. |
| */ |
| protected JpaContainerDefinition getJpaContainerDefinition(String typeName) { |
| if (typeName != null) { |
| for (JpaContainerDefinition definition : getJpaContainerDefinitions()) { |
| if (definition.isAssignableFrom(typeName)) { |
| return definition; |
| } |
| } |
| } |
| return JpaContainerDefinition.Null.instance(); |
| } |
| |
| protected Iterable<JpaContainerDefinition> getJpaContainerDefinitions() { |
| return JPA_CONTAINER_DEFINITIONS; |
| } |
| |
| protected static final JpaContainerDefinition[] JPA_CONTAINER_DEFINITION_ARRAY = new JpaContainerDefinition[] { |
| new CollectionJpaContainerDefinition(java.util.Set.class, JPA2_0.SET_ATTRIBUTE), |
| new CollectionJpaContainerDefinition(java.util.List.class, JPA2_0.LIST_ATTRIBUTE), |
| new CollectionJpaContainerDefinition(java.util.Collection.class, JPA2_0.COLLECTION_ATTRIBUTE), |
| new MapJpaContainerDefinition(java.util.Map.class, JPA2_0.MAP_ATTRIBUTE) |
| }; |
| |
| protected static final Iterable<JpaContainerDefinition> JPA_CONTAINER_DEFINITIONS = new ArrayIterable<JpaContainerDefinition>(JPA_CONTAINER_DEFINITION_ARRAY); |
| |
| |
| /** |
| * Abstract JPA container definition |
| */ |
| protected abstract static class AbstractJpaContainerDefinition |
| implements JpaContainerDefinition |
| { |
| protected final Class<?> containerClass; |
| protected final String metamodelContainerFieldTypeName; |
| |
| protected AbstractJpaContainerDefinition(Class<?> containerClass, String metamodelContainerFieldTypeName) { |
| super(); |
| if ((containerClass == null) || (metamodelContainerFieldTypeName == null)) { |
| throw new NullPointerException(); |
| } |
| this.containerClass = containerClass; |
| this.metamodelContainerFieldTypeName = metamodelContainerFieldTypeName; |
| } |
| |
| public boolean isAssignableFrom(String typeName) { |
| try { |
| return this.containerClass.isAssignableFrom(Class.forName(typeName)); |
| } |
| catch (ClassNotFoundException e) { |
| return false; |
| } |
| } |
| |
| public boolean isContainer() { |
| return true; |
| } |
| |
| public String getMetamodelContainerFieldTypeName() { |
| return this.metamodelContainerFieldTypeName; |
| } |
| |
| public String getMultiReferenceTargetTypeName(JavaResourceAttribute resourceAttribute) { |
| throw new UnsupportedOperationException(); |
| } |
| |
| public String getMultiReferenceMapKeyTypeName(JavaResourceAttribute resourceAttribute) { |
| throw new UnsupportedOperationException(); |
| } |
| } |
| |
| /** |
| * Collection JPA container definition |
| */ |
| protected static class CollectionJpaContainerDefinition |
| extends AbstractJpaContainerDefinition |
| { |
| protected CollectionJpaContainerDefinition(Class<?> collectionClass, String staticMetamodelTypeDeclarationTypeName) { |
| super(collectionClass, staticMetamodelTypeDeclarationTypeName); |
| } |
| |
| public String getMetamodelContainerFieldMapKeyTypeName(CollectionMapping mapping) { |
| return null; |
| } |
| |
| public boolean isMap() { |
| return false; |
| } |
| } |
| |
| /** |
| * Map JPA container definition |
| */ |
| protected static class MapJpaContainerDefinition |
| extends AbstractJpaContainerDefinition |
| { |
| protected MapJpaContainerDefinition(Class<?> mapClass, String staticMetamodelTypeDeclarationTypeName) { |
| super(mapClass, staticMetamodelTypeDeclarationTypeName); |
| } |
| |
| public String getMetamodelContainerFieldMapKeyTypeName(CollectionMapping mapping) { |
| return mapping.getMetamodelFieldMapKeyTypeName(); |
| } |
| |
| public boolean isMap() { |
| return true; |
| } |
| } |
| |
| |
| // ********** misc ********** |
| |
| @Override |
| public OrmPersistentType getParent() { |
| return (OrmPersistentType) super.getParent(); |
| } |
| |
| public OrmPersistentType getOwningPersistentType() { |
| return this.getParent(); |
| } |
| |
| public TypeMapping getOwningTypeMapping() { |
| return this.getOwningPersistentType().getMapping(); |
| } |
| |
| protected EntityMappings getEntityMappings() { |
| return (EntityMappings) getParent().getMappingFileRoot(); |
| } |
| |
| public String getPrimaryKeyColumnName() { |
| throw new UnsupportedOperationException("Owing orm persistent attribute should handle, this should not be called."); //$NON-NLS-1$ |
| } |
| |
| @Override |
| public void toString(StringBuilder sb) { |
| sb.append(this.getName()); |
| } |
| } |