| /******************************************************************************* |
| * Copyright (c) 2011, 2013 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.jaxb.core.internal.context.java; |
| |
| import java.util.HashSet; |
| import java.util.Hashtable; |
| import java.util.Iterator; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import org.eclipse.jpt.common.core.internal.utility.TypeTools; |
| import org.eclipse.jpt.common.core.resource.java.JavaResourceType; |
| import org.eclipse.jpt.common.core.utility.TextRange; |
| import org.eclipse.jpt.common.utility.collection.Bag; |
| import org.eclipse.jpt.common.utility.internal.ObjectTools; |
| import org.eclipse.jpt.common.utility.internal.StringTools; |
| import org.eclipse.jpt.common.utility.internal.collection.CollectionTools; |
| import org.eclipse.jpt.common.utility.internal.iterable.EmptyIterable; |
| import org.eclipse.jpt.common.utility.internal.iterable.EmptyListIterable; |
| import org.eclipse.jpt.common.utility.internal.iterable.IterableTools; |
| import org.eclipse.jpt.common.utility.internal.iterable.SingleElementIterable; |
| import org.eclipse.jpt.common.utility.iterable.ListIterable; |
| import org.eclipse.jpt.jaxb.core.MappingKeys; |
| import org.eclipse.jpt.jaxb.core.context.JaxbAttributeMapping; |
| import org.eclipse.jpt.jaxb.core.context.JaxbAttributesContainer; |
| import org.eclipse.jpt.jaxb.core.context.JaxbAttributesContainer.Context; |
| import org.eclipse.jpt.jaxb.core.context.JaxbClassMapping; |
| import org.eclipse.jpt.jaxb.core.context.JaxbPackage; |
| import org.eclipse.jpt.jaxb.core.context.JaxbPackageInfo; |
| import org.eclipse.jpt.jaxb.core.context.JaxbPersistentAttribute; |
| import org.eclipse.jpt.jaxb.core.context.XmlAccessOrder; |
| import org.eclipse.jpt.jaxb.core.context.XmlAccessType; |
| import org.eclipse.jpt.jaxb.core.context.XmlNamedNodeMapping; |
| import org.eclipse.jpt.jaxb.core.context.java.JavaClass; |
| import org.eclipse.jpt.jaxb.core.context.java.JavaClassMapping; |
| import org.eclipse.jpt.jaxb.core.context.java.JavaPersistentAttribute; |
| import org.eclipse.jpt.jaxb.core.context.java.JavaType; |
| import org.eclipse.jpt.jaxb.core.resource.java.JAXB; |
| import org.eclipse.jpt.jaxb.core.resource.java.XmlAccessorOrderAnnotation; |
| import org.eclipse.jpt.jaxb.core.resource.java.XmlAccessorTypeAnnotation; |
| import org.eclipse.jpt.jaxb.core.validation.JptJaxbCoreValidationMessages; |
| import org.eclipse.wst.validation.internal.provisional.core.IMessage; |
| import org.eclipse.wst.validation.internal.provisional.core.IReporter; |
| |
| |
| public class GenericJavaClassMapping |
| extends AbstractJavaTypeMapping |
| implements JavaClassMapping { |
| |
| protected String specifiedFactoryClass; |
| |
| protected String factoryMethod; |
| |
| protected final PropOrderContainer propOrderContainer; |
| |
| protected String superclassName; // used internally only |
| protected static final String SUPERCLASSNAME_PROPERTY = "superclassName"; //$NON-NLS-1$ - used only to trigger update |
| protected JaxbClassMapping superclass; |
| |
| protected XmlAccessType accessType; |
| protected XmlAccessType defaultAccessType; |
| protected XmlAccessType specifiedAccessType; |
| |
| protected XmlAccessOrder defaultAccessOrder; |
| protected XmlAccessOrder specifiedAccessOrder; |
| |
| protected boolean hasRootElementInHierarchy_loaded = false; |
| protected boolean hasRootElementInHierarchy = false; |
| |
| protected final JaxbAttributesContainer attributesContainer; |
| |
| protected final Map<JaxbClassMapping, JaxbAttributesContainer> includedAttributesContainers; |
| |
| public GenericJavaClassMapping(JavaClass parent) { |
| super(parent); |
| this.includedAttributesContainers = new Hashtable<JaxbClassMapping, JaxbAttributesContainer>(); |
| this.propOrderContainer = new PropOrderContainer(); |
| |
| initFactoryClass(); |
| initFactoryMethod(); |
| initPropOrder(); |
| initAccessType(); |
| initSpecifiedAccessOrder(); |
| initDefaultAccessOrder(); |
| initSuperclassName(); |
| this.attributesContainer = new GenericJavaAttributesContainer(this, buildAttributesContainerOwner(), getJavaResourceType()); |
| } |
| |
| |
| @Override |
| public JavaResourceType getJavaResourceType() { |
| return (JavaResourceType) super.getJavaResourceType(); |
| } |
| |
| @Override |
| public JavaClass getJavaType() { |
| return (JavaClass) super.getJavaType(); |
| } |
| |
| public JaxbPackageInfo getPackageInfo() { |
| JaxbPackage jaxbPackage = getJaxbPackage(); |
| // jaxb package may be null during initialization/update |
| return (jaxbPackage == null) ? null : jaxbPackage.getPackageInfo(); |
| } |
| |
| |
| // ***** sync/update ***** |
| |
| @Override |
| public void synchronizeWithResourceModel() { |
| super.synchronizeWithResourceModel(); |
| syncFactoryClass(); |
| syncFactoryMethod(); |
| syncPropOrder(); |
| syncAccessType(); |
| syncSpecifiedAccessOrder(); |
| syncSuperclassName(); |
| this.attributesContainer.synchronizeWithResourceModel(); |
| syncIncludedAttributes(); |
| } |
| |
| @Override |
| public void update() { |
| super.update(); |
| updateSuperclass(); // done first because much depends on it |
| updateAccessType(); |
| updateDefaultAccessOrder(); |
| this.hasRootElementInHierarchy_loaded = false; // triggers that the value must be recalculated on next request |
| this.attributesContainer.update(); |
| updateIncludedAttributes(); |
| } |
| |
| |
| // ***** factory class ***** |
| |
| public String getFactoryClass() { |
| return (this.specifiedFactoryClass != null) ? this.specifiedFactoryClass : JAXB.XML_TYPE__DEFAULT_FACTORY_CLASS; |
| } |
| |
| public String getSpecifiedFactoryClass() { |
| return this.specifiedFactoryClass; |
| } |
| |
| public void setSpecifiedFactoryClass(String factoryClass) { |
| getXmlTypeAnnotation().setFactoryClass(factoryClass); |
| setSpecifiedFactoryClass_(factoryClass); |
| } |
| |
| protected void setSpecifiedFactoryClass_(String factoryClass) { |
| String old = this.specifiedFactoryClass; |
| this.specifiedFactoryClass = factoryClass; |
| firePropertyChanged(SPECIFIED_FACTORY_CLASS_PROPERTY, old, factoryClass); |
| } |
| |
| protected String getResourceFactoryClass() { |
| return getXmlTypeAnnotation().getFactoryClass(); |
| } |
| |
| protected void initFactoryClass() { |
| this.specifiedFactoryClass = getResourceFactoryClass(); |
| } |
| |
| protected void syncFactoryClass() { |
| setSpecifiedFactoryClass_(getResourceFactoryClass()); |
| } |
| |
| |
| // ***** factory method ***** |
| |
| public String getFactoryMethod() { |
| return this.factoryMethod; |
| } |
| |
| public void setFactoryMethod(String factoryMethod) { |
| getXmlTypeAnnotation().setFactoryMethod(factoryMethod); |
| setFactoryMethod_(factoryMethod); |
| } |
| |
| protected void setFactoryMethod_(String factoryMethod) { |
| String old = this.factoryMethod; |
| this.factoryMethod = factoryMethod; |
| firePropertyChanged(FACTORY_METHOD_PROPERTY, old, factoryMethod); |
| } |
| |
| protected String getResourceFactoryMethod() { |
| return getXmlTypeAnnotation().getFactoryMethod(); |
| } |
| |
| protected void initFactoryMethod() { |
| this.factoryMethod = getResourceFactoryMethod(); |
| } |
| |
| protected void syncFactoryMethod() { |
| setFactoryMethod_(getResourceFactoryMethod()); |
| } |
| |
| |
| // ***** prop order ***** |
| |
| public ListIterable<String> getPropOrder() { |
| return this.propOrderContainer.getContextElements(); |
| } |
| |
| public String getProp(int index) { |
| return this.propOrderContainer.getContextElement(index); |
| } |
| |
| public int getPropOrderSize() { |
| return this.propOrderContainer.getContextElementsSize(); |
| } |
| |
| public void addProp(int index, String prop) { |
| getXmlTypeAnnotation().addProp(index, prop); |
| this.propOrderContainer.addContextElement(index, prop); |
| } |
| |
| public void removeProp(String prop) { |
| this.removeProp(this.propOrderContainer.indexOfContextElement(prop)); |
| } |
| |
| public void removeProp(int index) { |
| this.getXmlTypeAnnotation().removeProp(index); |
| this.propOrderContainer.removeContextElement(index); |
| } |
| |
| public void moveProp(int targetIndex, int sourceIndex) { |
| this.getXmlTypeAnnotation().moveProp(targetIndex, sourceIndex); |
| this.propOrderContainer.moveContextElement(targetIndex, sourceIndex); |
| } |
| |
| protected void initPropOrder() { |
| this.propOrderContainer.initialize(); |
| } |
| |
| protected void syncPropOrder() { |
| this.propOrderContainer.synchronizeWithResourceModel(); |
| } |
| |
| protected ListIterable<String> getResourcePropOrder() { |
| ListIterable<String> result = getXmlTypeAnnotation().getPropOrder(); |
| if (IterableTools.size(result) == 1 && StringTools.EMPTY_STRING.equals(IterableTools.get(result, 0))) { |
| return EmptyListIterable.instance(); |
| } |
| return result; |
| } |
| |
| |
| // ***** XmlAccessorType ***** |
| |
| public XmlAccessType getAccessType() { |
| return this.accessType; |
| } |
| |
| protected void setAccessType_(XmlAccessType accessType) { |
| XmlAccessType old = this.accessType; |
| this.accessType = accessType; |
| firePropertyChanged(ACCESS_TYPE_PROPERTY, old, accessType); |
| } |
| |
| public XmlAccessType getDefaultAccessType() { |
| return this.defaultAccessType; |
| } |
| |
| protected void setDefaultAccessType_(XmlAccessType access) { |
| XmlAccessType old = this.defaultAccessType; |
| this.defaultAccessType = access; |
| firePropertyChanged(DEFAULT_ACCESS_TYPE_PROPERTY, old, access); |
| } |
| |
| public XmlAccessType getSpecifiedAccessType() { |
| return this.specifiedAccessType; |
| } |
| |
| public void setSpecifiedAccessType(XmlAccessType access) { |
| getXmlAccessorTypeAnnotation().setValue(XmlAccessType.toJavaResourceModel(access)); |
| setSpecifiedAccessType_(access); |
| } |
| |
| protected void setSpecifiedAccessType_(XmlAccessType access) { |
| XmlAccessType old = this.specifiedAccessType; |
| this.specifiedAccessType = access; |
| firePropertyChanged(SPECIFIED_ACCESS_TYPE_PROPERTY, old, access); |
| } |
| |
| protected void initAccessType() { |
| this.specifiedAccessType = getResourceAccessType(); |
| } |
| |
| protected void syncAccessType() { |
| setSpecifiedAccessType(getResourceAccessType()); |
| } |
| |
| protected void updateAccessType() { |
| setDefaultAccessType_(buildDefaultAccessType()); |
| |
| XmlAccessType actual = (this.specifiedAccessType != null) ? |
| this.specifiedAccessType |
| : this.defaultAccessType; |
| setAccessType_(actual); |
| } |
| |
| /** |
| * Default access type is determined by the following, in order of precedence: |
| * - @XmlAccessorType annotation on a mapped (or transient, apparently) super class |
| * - @XmlAccessorType annotation on the package |
| * - default access type of {@link XmlAccessType#PUBLIC_MEMBER} |
| */ |
| protected XmlAccessType buildDefaultAccessType() { |
| XmlAccessType accessType = getSuperclassAccessType(); |
| if (accessType != null) { |
| return accessType; |
| } |
| accessType = getPackageAccessType(); |
| if (accessType != null) { |
| return accessType; |
| } |
| return XmlAccessType.PUBLIC_MEMBER; |
| } |
| |
| protected XmlAccessType getSuperclassAccessType() { |
| JaxbClassMapping superclass = this.superclass; |
| while (superclass != null) { |
| XmlAccessType accessType = superclass.getSpecifiedAccessType(); |
| if (accessType != null) { |
| return accessType; |
| } |
| superclass = superclass.getSuperclass(); |
| } |
| return null; |
| } |
| |
| protected XmlAccessType getPackageAccessType() { |
| JaxbPackageInfo packageInfo = getPackageInfo(); |
| return (packageInfo == null) ? null : packageInfo.getAccessType(); |
| } |
| |
| protected XmlAccessorTypeAnnotation getXmlAccessorTypeAnnotation() { |
| return (XmlAccessorTypeAnnotation) getJavaResourceType().getNonNullAnnotation(JAXB.XML_ACCESSOR_TYPE); |
| } |
| |
| protected XmlAccessType getResourceAccessType() { |
| return XmlAccessType.fromJavaResourceModel(getXmlAccessorTypeAnnotation().getValue()); |
| } |
| |
| |
| // ***** XmlAccessorOrder ***** |
| |
| public XmlAccessOrder getAccessOrder() { |
| return (this.specifiedAccessOrder != null) ? this.specifiedAccessOrder : this.defaultAccessOrder; |
| } |
| |
| public XmlAccessOrder getDefaultAccessOrder() { |
| return this.defaultAccessOrder; |
| } |
| |
| protected void setDefaultAccessOrder_(XmlAccessOrder accessOrder) { |
| XmlAccessOrder old = this.defaultAccessOrder; |
| this.defaultAccessOrder = accessOrder; |
| firePropertyChanged(DEFAULT_ACCESS_ORDER_PROPERTY, old, accessOrder); |
| } |
| |
| public XmlAccessOrder getSpecifiedAccessOrder() { |
| return this.specifiedAccessOrder; |
| } |
| |
| public void setSpecifiedAccessOrder(XmlAccessOrder accessOrder) { |
| getXmlAccessorOrderAnnotation().setValue(XmlAccessOrder.toJavaResourceModel(accessOrder)); |
| setSpecifiedAccessOrder_(accessOrder); |
| } |
| |
| protected void setSpecifiedAccessOrder_(XmlAccessOrder accessOrder) { |
| XmlAccessOrder old = this.specifiedAccessOrder; |
| this.specifiedAccessOrder = accessOrder; |
| firePropertyChanged(SPECIFIED_ACCESS_ORDER_PROPERTY, old, accessOrder); |
| } |
| |
| protected void initDefaultAccessOrder() { |
| this.defaultAccessOrder = buildDefaultAccessOrder(); |
| } |
| |
| protected void updateDefaultAccessOrder() { |
| setDefaultAccessOrder_(buildDefaultAccessOrder()); |
| } |
| |
| /** |
| * Default access order is determined by the following, in order of precedence: |
| * - @XmlAccessorOrder annotation on a mapped (or transient, apparently) super class |
| * - @XmlAccessorOrder annotation on the package |
| * - default access order of {@link UNDEFINED} |
| */ |
| protected XmlAccessOrder buildDefaultAccessOrder() { |
| XmlAccessOrder accessOrder = getSuperclassAccessOrder(); |
| if (accessOrder != null) { |
| return accessOrder; |
| } |
| accessOrder = getPackageAccessOrder(); |
| if (accessOrder != null) { |
| return accessOrder; |
| } |
| return XmlAccessOrder.UNDEFINED; |
| } |
| |
| protected XmlAccessOrder getSuperclassAccessOrder() { |
| JaxbClassMapping superclass = this.superclass; |
| while (superclass != null) { |
| XmlAccessOrder accessOrder = superclass.getSpecifiedAccessOrder(); |
| if (accessOrder != null) { |
| return accessOrder; |
| } |
| superclass = superclass.getSuperclass(); |
| } |
| return null; |
| } |
| |
| protected XmlAccessOrder getPackageAccessOrder() { |
| JaxbPackageInfo packageInfo = getPackageInfo(); |
| return packageInfo == null ? null : packageInfo.getAccessOrder(); |
| } |
| |
| protected XmlAccessorOrderAnnotation getXmlAccessorOrderAnnotation() { |
| return (XmlAccessorOrderAnnotation) getJavaResourceType().getNonNullAnnotation(JAXB.XML_ACCESSOR_ORDER); |
| } |
| |
| protected XmlAccessOrder getResourceAccessOrder() { |
| return XmlAccessOrder.fromJavaResourceModel(getXmlAccessorOrderAnnotation().getValue()); |
| } |
| |
| protected void initSpecifiedAccessOrder() { |
| this.specifiedAccessOrder = getResourceAccessOrder(); |
| } |
| |
| protected void syncSpecifiedAccessOrder() { |
| setSpecifiedAccessOrder_(getResourceAccessOrder()); |
| } |
| |
| |
| // ********** super class ********** |
| |
| protected void initSuperclassName() { |
| this.superclassName = getResourceSuperclassName(); |
| } |
| |
| protected void syncSuperclassName() { |
| String old = this.superclassName; |
| this.superclassName = getResourceSuperclassName(); |
| firePropertyChanged(SUPERCLASSNAME_PROPERTY, old, this.superclassName); |
| } |
| |
| protected String getResourceSuperclassName() { |
| return getJavaResourceType().getSuperclassQualifiedName(); |
| } |
| |
| public JaxbClassMapping getSuperclass() { |
| return this.superclass; |
| } |
| |
| protected void setSuperclass_(JaxbClassMapping superclass) { |
| JaxbClassMapping old = this.superclass; |
| this.superclass = superclass; |
| this.firePropertyChanged(SUPERCLASS_PROPERTY, old, superclass); |
| } |
| |
| protected void updateSuperclass() { |
| setSuperclass_(findSuperclass()); |
| } |
| |
| protected JaxbClassMapping findSuperclass() { |
| if (this.superclassName != null) { |
| return getJaxbProject().getContextRoot().getClassMapping(this.superclassName); |
| } |
| return null; |
| } |
| |
| |
| // ***** attributes ***** |
| |
| public Iterable<JavaPersistentAttribute> getAttributes() { |
| return this.attributesContainer.getAttributes(); |
| } |
| |
| public int getAttributesSize() { |
| return this.attributesContainer.getAttributesSize(); |
| } |
| |
| protected GenericJavaAttributesContainer.Context buildAttributesContainerOwner() { |
| return new GenericJavaAttributesContainer.Context() { |
| public XmlAccessType getAccessType() { |
| return GenericJavaClassMapping.this.getAccessType(); |
| } |
| |
| public void attributeAdded(JaxbPersistentAttribute attribute) { |
| GenericJavaClassMapping.this.fireItemAdded(ATTRIBUTES_COLLECTION, attribute); |
| } |
| |
| public void attributeRemoved(JaxbPersistentAttribute attribute) { |
| GenericJavaClassMapping.this.fireItemRemoved(ATTRIBUTES_COLLECTION, attribute); |
| } |
| }; |
| } |
| |
| |
| // ***** included attributes ***** |
| |
| public Iterable<JaxbPersistentAttribute> getIncludedAttributes() { |
| return IterableTools.children(getIncludedAttributesContainers(), JaxbAttributesContainer.ATTRIBUTES_TRANSFORMER); |
| } |
| |
| protected Iterable<JaxbAttributesContainer> getIncludedAttributesContainers() { |
| return IterableTools.cloneLive(this.includedAttributesContainers.values()); // read-only |
| } |
| |
| public int getIncludedAttributesSize() { |
| int size = 0; |
| for (JaxbAttributesContainer attributesContainer : getIncludedAttributesContainers()) { |
| size += attributesContainer.getAttributesSize(); |
| } |
| return size; |
| } |
| |
| protected void syncIncludedAttributes() { |
| for (JaxbAttributesContainer attributesContainer : this.includedAttributesContainers.values()) { |
| attributesContainer.synchronizeWithResourceModel(); |
| } |
| } |
| |
| protected void updateIncludedAttributes() { |
| HashSet<JaxbClassMapping> oldSuperclasses |
| = CollectionTools.set(this.includedAttributesContainers.keySet()); |
| Set<JaxbPersistentAttribute> oldAttributes = CollectionTools.set(getIncludedAttributes()); |
| |
| if (! isXmlTransient()) { |
| JaxbClassMapping superclass = this.superclass; |
| // only add inherited attributes for superclasses up until a mapped class is encountered |
| while (superclass != null && superclass.isXmlTransient()) { |
| if (this.includedAttributesContainers.containsKey(superclass)) { |
| this.includedAttributesContainers.get(superclass).update(); |
| oldSuperclasses.remove(superclass); |
| } |
| else { |
| this.includedAttributesContainers.put(superclass, buildIncludedAttributesContainer(superclass)); |
| } |
| superclass = superclass.getSuperclass(); |
| } |
| } |
| |
| for (JaxbClassMapping oldSuperclass : oldSuperclasses) { |
| this.includedAttributesContainers.remove(oldSuperclass); |
| } |
| |
| Set<JaxbPersistentAttribute> newAttributes = CollectionTools.set(getIncludedAttributes()); |
| if (IterableTools.elementsAreDifferent(oldAttributes, newAttributes)) { |
| fireCollectionChanged(INCLUDED_ATTRIBUTES_COLLECTION, newAttributes); |
| } |
| } |
| |
| protected JaxbAttributesContainer buildIncludedAttributesContainer(JaxbClassMapping classMapping) { |
| return classMapping.buildIncludedAttributesContainer(this, buildIncludedAttributesContainerOwner()); |
| } |
| |
| protected JaxbAttributesContainer.Context buildIncludedAttributesContainerOwner() { |
| return new GenericJavaAttributesContainer.Context() { |
| public XmlAccessType getAccessType() { |
| return GenericJavaClassMapping.this.getAccessType(); |
| } |
| |
| public void attributeAdded(JaxbPersistentAttribute attribute) { |
| GenericJavaClassMapping.this.fireItemAdded(INCLUDED_ATTRIBUTES_COLLECTION, attribute); |
| } |
| |
| public void attributeRemoved(JaxbPersistentAttribute attribute) { |
| GenericJavaClassMapping.this.fireItemRemoved(INCLUDED_ATTRIBUTES_COLLECTION, attribute); |
| } |
| }; |
| } |
| |
| public JaxbAttributesContainer buildIncludedAttributesContainer(JaxbClassMapping parent, Context context) { |
| return new GenericJavaAttributesContainer(parent, context, getJavaResourceType()); |
| } |
| |
| |
| // ***** misc attributes ***** |
| |
| public Iterable<JaxbPersistentAttribute> getAllLocallyDefinedAttributes() { |
| return IterableTools.concatenate( |
| getAttributes(), |
| getIncludedAttributes()); |
| } |
| |
| public Iterable<JaxbPersistentAttribute> getInheritedAttributes() { |
| return IterableTools.concatenate( |
| getIncludedAttributes(), |
| getOtherInheritedAttributes()); |
| } |
| |
| public Iterable<JaxbPersistentAttribute> getAllAttributes() { |
| return IterableTools.concatenate( |
| getAttributes(), |
| getIncludedAttributes(), |
| getOtherInheritedAttributes()); |
| } |
| |
| /** |
| * return those inherited attributes that are not included |
| */ |
| protected Iterable<JaxbPersistentAttribute> getOtherInheritedAttributes() { |
| return (this.superclass == null) ? |
| IterableTools.<JaxbPersistentAttribute>emptyIterable() : |
| IterableTools.children( |
| ObjectTools.chain(this.superclass, JaxbClassMapping.SUPER_CLASS_TRANSFORMER), |
| JaxbClassMapping.ATTRIBUTES_TRANSFORMER |
| ); |
| } |
| |
| |
| // ***** subClasses ***** |
| |
| @Override |
| public boolean hasRootElementInHierarchy() { |
| if (! this.hasRootElementInHierarchy_loaded) { |
| this.hasRootElementInHierarchy = calculateHasRootElementInHierarchy(); |
| this.hasRootElementInHierarchy_loaded = true; |
| } |
| return this.hasRootElementInHierarchy; |
| } |
| |
| protected boolean calculateHasRootElementInHierarchy() { |
| if (this.getXmlRootElement() != null) { |
| return true; |
| } |
| |
| for (JavaType jaxbType : getJaxbProject().getContextRoot().getJavaTypes()) { |
| if (jaxbType.getMapping() != null |
| && ! jaxbType.getMapping().isXmlTransient() |
| && jaxbType.getMapping().getXmlRootElement() != null |
| && TypeTools.isSubType( |
| jaxbType.getTypeName().getFullyQualifiedName(), getJavaType().getTypeName().getFullyQualifiedName(), getJaxbProject().getJavaProject())) { |
| return true; |
| } |
| } |
| |
| return false; |
| } |
| |
| |
| // ***** misc ***** |
| |
| @Override |
| protected Iterable<String> getTransientReferencedXmlTypeNames() { |
| return IterableTools.concatenate( |
| super.getTransientReferencedXmlTypeNames(), |
| new SingleElementIterable(getJavaResourceType().getSuperclassQualifiedName())); |
| } |
| |
| @Override |
| protected Iterable<String> getNonTransientReferencedXmlTypeNames() { |
| return IterableTools.concatenate( |
| super.getNonTransientReferencedXmlTypeNames(), |
| IterableTools.singletonIterable(this.superclassName), |
| IterableTools.children(getAttributeMappings(), JaxbAttributeMapping.REFERENCED_XML_TYPE_NAMES_TRANSFORMER)); |
| } |
| |
| public JaxbAttributeMapping getXmlIdMapping() { |
| Iterator<XmlNamedNodeMapping> allXmlIdMappings = |
| IterableTools.filter( |
| IterableTools.<JaxbAttributeMapping, XmlNamedNodeMapping>downCast( |
| IterableTools.filter( |
| IterableTools.transform( |
| getAllAttributes(), |
| JaxbPersistentAttribute.MAPPING_TRANSFORMER), |
| XmlNamedNodeMapping.IS_NAMED_NODE_MAPPING)), |
| XmlNamedNodeMapping.HAS_XML_ID).iterator(); |
| return allXmlIdMappings.hasNext() ? allXmlIdMappings.next() : null; |
| } |
| |
| protected Iterable<? extends JaxbAttributeMapping> getAttributeMappings() { |
| return IterableTools.transform(getAttributes(), JaxbPersistentAttribute.MAPPING_TRANSFORMER); |
| } |
| |
| |
| // ***** content assist ***** |
| |
| @Override |
| public Iterable<String> getCompletionProposals(int pos) { |
| |
| Iterable<String> result = super.getCompletionProposals(pos); |
| if (! IterableTools.isEmpty(result)) { |
| return result; |
| } |
| |
| if (propTouches(pos)) { |
| return getPropProposals(); |
| } |
| |
| // TODO - factory methods? |
| |
| for (JaxbPersistentAttribute attribute : this.getAttributes()) { |
| result = attribute.getCompletionProposals(pos); |
| if (!IterableTools.isEmpty(result)) { |
| return result; |
| } |
| } |
| |
| return EmptyIterable.instance(); |
| } |
| |
| protected Iterable<String> getPropProposals() { |
| return IterableTools.transform( |
| IterableTools.transform( |
| getAllLocallyDefinedAttributes(), |
| JaxbPersistentAttribute.NAME_TRANSFORMER), |
| StringTools.JAVA_STRING_LITERAL_CONTENT_TRANSFORMER); |
| } |
| |
| |
| // ***** validation ***** |
| |
| @Override |
| public void validate(List<IMessage> messages, IReporter reporter) { |
| super.validate(messages, reporter); |
| |
| validateConstructor(messages, reporter); |
| validatePropOrder(messages, reporter); |
| validateXmlAnyAttributeMapping(messages); |
| validateXmlAnyElementMapping(messages); |
| validateXmlValueMapping(messages); |
| validateXmlIDs(messages); |
| |
| for (JaxbPersistentAttribute attribute : getAttributes()) { |
| attribute.validate(messages, reporter); |
| } |
| } |
| |
| protected void validateConstructor(List<IMessage> messages, IReporter reporter) { |
| // TODO - factory class/method |
| |
| if (! JAXB.XML_TYPE__DEFAULT_FACTORY_CLASS.equals(getFactoryClass())) { |
| if (StringTools.isBlank(getFactoryMethod())) { |
| messages.add( |
| this.buildValidationMessage( |
| getFactoryClassTextRange(), |
| JptJaxbCoreValidationMessages.XML_TYPE__UNSPECIFIED_FACTORY_METHOD |
| )); |
| } |
| } |
| else { |
| if (getFactoryMethod() == null |
| && getJavaType().getXmlJavaTypeAdapter() == null |
| && ! getJavaResourceType().hasPublicOrProtectedNoArgConstructor()) { |
| messages.add( |
| this.buildValidationMessage( |
| getValidationTextRange(), |
| JptJaxbCoreValidationMessages.XML_TYPE__NO_PUBLIC_OR_PROTECTED_CONSTRUCTOR |
| )); |
| } |
| } |
| |
| } |
| |
| protected void validatePropOrder(List<IMessage> messages, IReporter reporter) { |
| if (IterableTools.isEmpty(getPropOrder())) { |
| return; |
| } |
| |
| // no duplicates |
| // all attributes/included attributes with XmlElement/s/Ref/s must be listed |
| // no nonexistent attributes (attributes mapped otherwise allowed) ... |
| // *except* no transient attributes allowed |
| |
| Bag<String> props = CollectionTools.bag(getPropOrder()); |
| Set<String> allAttributes = new HashSet<String>(); |
| Set<String> requiredAttributes = new HashSet<String>(); |
| Set<String> transientAttributes = new HashSet<String>(); |
| |
| for (JaxbPersistentAttribute attribute : getAllLocallyDefinedAttributes()) { |
| allAttributes.add(attribute.getName()); |
| transientAttributes.add(attribute.getName()); |
| } |
| |
| for (JaxbPersistentAttribute attribute : getAllLocallyDefinedAttributes()) { |
| if (attribute.getMapping().isParticleMapping()) { |
| requiredAttributes.add(attribute.getName()); |
| } |
| |
| if (! attribute.getMapping().isTransient()) { |
| // remove transients (rather than previous algorithm of adding them) |
| // there may be two attributes of the same name (one field, one property) in |
| // a class, which is a correct configuration. we want to know if *every* attribute |
| // of a given name is transient (or if there's a single non-transient attribute) |
| transientAttributes.remove(attribute.getName()); |
| } |
| } |
| |
| Set<Integer> duplicateProps = new HashSet<Integer>(); |
| Set<String> missingProps = new HashSet<String>(requiredAttributes); |
| Set<Integer> nonexistentProps = new HashSet<Integer>(); |
| Set<Integer> transientProps = new HashSet<Integer>(); |
| |
| for (int i = 0; i < getPropOrderSize(); i ++ ) { |
| String prop = getProp(i); |
| |
| if (props.count(prop) > 1) { |
| duplicateProps.add(i); |
| } |
| |
| if (missingProps.contains(prop)) { |
| missingProps.remove(prop); |
| } |
| |
| if (! allAttributes.contains(prop)) { |
| nonexistentProps.add(i); |
| } |
| |
| if (transientAttributes.contains(prop)) { |
| transientProps.add(i); |
| } |
| } |
| |
| for (int i : duplicateProps) { |
| messages.add( |
| this.buildValidationMessage( |
| getPropTextRange(i), |
| JptJaxbCoreValidationMessages.XML_TYPE__DUPLICATE_PROP, |
| getProp(i))); |
| } |
| |
| for (String missingProp : missingProps) { |
| messages.add( |
| this.buildValidationMessage( |
| getPropOrderTextRange(), |
| JptJaxbCoreValidationMessages.XML_TYPE__MISSING_PROP, |
| missingProp)); |
| } |
| |
| for (int i : nonexistentProps) { |
| messages.add( |
| this.buildValidationMessage( |
| getPropTextRange(i), |
| JptJaxbCoreValidationMessages.XML_TYPE__NONEXISTENT_PROP, |
| getProp(i))); |
| } |
| |
| for (int i : transientProps) { |
| messages.add( |
| this.buildValidationMessage( |
| getPropTextRange(i), |
| JptJaxbCoreValidationMessages.XML_TYPE__TRANSIENT_PROP, |
| getProp(i))); |
| } |
| } |
| |
| protected void validateXmlAnyAttributeMapping(List<IMessage> messages) { |
| Set<JaxbPersistentAttribute> localAttributes = new HashSet<JaxbPersistentAttribute>(); |
| Set<JaxbPersistentAttribute> allAttributes = new HashSet<JaxbPersistentAttribute>(); |
| |
| for (JaxbPersistentAttribute attribute : getAttributes()) { |
| if (attribute.getMappingKey() == MappingKeys.XML_ANY_ATTRIBUTE_ATTRIBUTE_MAPPING_KEY) { |
| localAttributes.add(attribute); |
| allAttributes.add(attribute); |
| } |
| } |
| |
| for (JaxbPersistentAttribute attribute : getInheritedAttributes()) { |
| if (attribute.getMappingKey() == MappingKeys.XML_ANY_ATTRIBUTE_ATTRIBUTE_MAPPING_KEY) { |
| allAttributes.add(attribute); |
| } |
| } |
| |
| if (allAttributes.size() > 1) { |
| messages.add( |
| this.buildValidationMessage( |
| getValidationTextRange(), |
| JptJaxbCoreValidationMessages.XML_ANY_ATTRIBUTE__MULTIPLE_MAPPINGS_DEFINED |
| )); |
| |
| for (JaxbPersistentAttribute anyAttribute : localAttributes) { |
| messages.add( |
| this.buildValidationMessage( |
| anyAttribute.getMapping(), |
| anyAttribute.getMapping().getValidationTextRange(), |
| JptJaxbCoreValidationMessages.XML_ANY_ATTRIBUTE__MULTIPLE_MAPPINGS_DEFINED |
| )); |
| } |
| } |
| } |
| |
| protected void validateXmlAnyElementMapping(List<IMessage> messages) { |
| Set<JaxbPersistentAttribute> localAttributes = new HashSet<JaxbPersistentAttribute>(); |
| Set<JaxbPersistentAttribute> allAttributes = new HashSet<JaxbPersistentAttribute>(); |
| |
| for (JaxbPersistentAttribute attribute : getAttributes()) { |
| if (attribute.getMappingKey() == MappingKeys.XML_ANY_ELEMENT_ATTRIBUTE_MAPPING_KEY) { |
| localAttributes.add(attribute); |
| allAttributes.add(attribute); |
| } |
| } |
| |
| for (JaxbPersistentAttribute attribute : getInheritedAttributes()) { |
| if (attribute.getMappingKey() == MappingKeys.XML_ANY_ELEMENT_ATTRIBUTE_MAPPING_KEY) { |
| allAttributes.add(attribute); |
| } |
| } |
| |
| if (allAttributes.size() > 1) { |
| messages.add( |
| this.buildValidationMessage( |
| getValidationTextRange(), |
| JptJaxbCoreValidationMessages.XML_ANY_ELEMENT__MULTIPLE_MAPPINGS_DEFINED |
| )); |
| |
| for (JaxbPersistentAttribute anyAttribute : localAttributes) { |
| messages.add( |
| this.buildValidationMessage( |
| anyAttribute.getMapping(), |
| anyAttribute.getMapping().getValidationTextRange(), |
| JptJaxbCoreValidationMessages.XML_ANY_ELEMENT__MULTIPLE_MAPPINGS_DEFINED |
| )); |
| } |
| } |
| } |
| |
| protected void validateXmlValueMapping(List<IMessage> messages) { |
| Set<JaxbPersistentAttribute> localAttributes = new HashSet<JaxbPersistentAttribute>(); |
| Set<JaxbPersistentAttribute> allAttributes = new HashSet<JaxbPersistentAttribute>(); |
| |
| for (JaxbPersistentAttribute attribute : getAttributes()) { |
| if (attribute.getMappingKey() == MappingKeys.XML_VALUE_ATTRIBUTE_MAPPING_KEY) { |
| localAttributes.add(attribute); |
| allAttributes.add(attribute); |
| } |
| } |
| |
| for (JaxbPersistentAttribute attribute : getInheritedAttributes()) { |
| if (attribute.getMappingKey() == MappingKeys.XML_VALUE_ATTRIBUTE_MAPPING_KEY) { |
| allAttributes.add(attribute); |
| } |
| } |
| |
| if (allAttributes.size() > 1) { |
| messages.add( |
| this.buildValidationMessage( |
| getValidationTextRange(), |
| JptJaxbCoreValidationMessages.XML_VALUE__MULTIPLE_MAPPINGS_DEFINED |
| )); |
| |
| for (JaxbPersistentAttribute anyAttribute : localAttributes) { |
| messages.add( |
| this.buildValidationMessage( |
| anyAttribute.getMapping(), |
| anyAttribute.getMapping().getValidationTextRange(), |
| JptJaxbCoreValidationMessages.XML_VALUE__MULTIPLE_MAPPINGS_DEFINED |
| )); |
| } |
| } |
| } |
| |
| protected void validateXmlIDs(List<IMessage> messages) { |
| |
| Set<JaxbPersistentAttribute> localAttributes = new HashSet<JaxbPersistentAttribute>(); |
| Set<JaxbPersistentAttribute> allAttributes = new HashSet<JaxbPersistentAttribute>(); |
| |
| for (JaxbPersistentAttribute attribute : getAttributes()) { |
| if ((attribute.getMappingKey() == MappingKeys.XML_ATTRIBUTE_ATTRIBUTE_MAPPING_KEY |
| || attribute.getMappingKey() == MappingKeys.XML_ELEMENT_ATTRIBUTE_MAPPING_KEY) |
| && ((XmlNamedNodeMapping) attribute.getMapping()).getXmlID() != null) { |
| localAttributes.add(attribute); |
| allAttributes.add(attribute); |
| } |
| } |
| |
| for (JaxbPersistentAttribute attribute : getInheritedAttributes()) { |
| if ((attribute.getMappingKey() == MappingKeys.XML_ATTRIBUTE_ATTRIBUTE_MAPPING_KEY |
| || attribute.getMappingKey() == MappingKeys.XML_ELEMENT_ATTRIBUTE_MAPPING_KEY) |
| && ((XmlNamedNodeMapping) attribute.getMapping()).getXmlID() != null) { |
| allAttributes.add(attribute); |
| } |
| } |
| |
| if (allAttributes.size() > 1) { |
| messages.add( |
| this.buildValidationMessage( |
| getValidationTextRange(), |
| JptJaxbCoreValidationMessages.XML_ID__MULTIPLE_MAPPINGS_DEFINED |
| )); |
| |
| for (JaxbPersistentAttribute anyAttribute : localAttributes) { |
| messages.add( |
| this.buildValidationMessage( |
| anyAttribute.getMapping(), |
| anyAttribute.getMapping().getValidationTextRange(), |
| JptJaxbCoreValidationMessages.XML_ID__MULTIPLE_MAPPINGS_DEFINED |
| )); |
| } |
| } |
| } |
| |
| protected TextRange getFactoryClassTextRange() { |
| TextRange result = getXmlTypeAnnotation().getFactoryClassTextRange(); |
| return (result != null) ? result : getValidationTextRange(); |
| } |
| |
| protected TextRange getFactoryMethodTextRange() { |
| TextRange result = getXmlTypeAnnotation().getFactoryMethodTextRange(); |
| return (result != null) ? result : getValidationTextRange(); |
| } |
| |
| protected TextRange getPropOrderTextRange() { |
| TextRange result = getXmlTypeAnnotation().getPropOrderTextRange(); |
| return (result != null) ? result : getValidationTextRange(); |
| } |
| |
| protected TextRange getPropTextRange(int index) { |
| return getXmlTypeAnnotation().getPropTextRange(index); |
| } |
| |
| protected boolean propTouches(int pos) { |
| if (getXmlTypeAnnotation().propOrderTouches(pos)) { |
| for (int i = 0; i < getXmlTypeAnnotation().getPropOrderSize(); i ++ ) { |
| if (getXmlTypeAnnotation().propTouches(i, pos)) { |
| return true; |
| } |
| } |
| } |
| return false; |
| } |
| |
| |
| /** |
| * xml prop order container |
| */ |
| protected class PropOrderContainer |
| extends ListContainer<String, String> { |
| |
| @Override |
| protected String getContextElementsPropertyName() { |
| return PROP_ORDER_LIST; |
| } |
| |
| @Override |
| protected String buildContextElement(String resourceElement) { |
| return resourceElement; |
| } |
| |
| @Override |
| protected ListIterable<String> getResourceElements() { |
| return GenericJavaClassMapping.this.getResourcePropOrder(); |
| } |
| |
| @Override |
| protected String getResourceElement(String contextElement) { |
| return contextElement; |
| } |
| } |
| } |