/** * Construct an element key with the given id, datatype, and element type. * This is used for elements that contain text content. * * <p>The {@code elementType} must not be {@code null}. A null id is only * valid for element types that are a subclass of {@link Element}, and are * used as a key referring to all instances of that element type. */ public static <T, V extends Element> ElementKey<T, V> of(QName id, Class<? extends T> datatype, Class<? extends V> elementType) { return new ElementKey<T, V>(id, datatype, elementType); }
/** * Compares first on ID, then on element type, then on datatype. */ public int compareTo(MetadataKey<?> other) { if (other == this) { return 0; } // If they aren't the same type, put element keys at the end. if (!(other instanceof ElementKey<?, ?>)) { return 1; } int compare = compareQName(id, other.id); if (compare != 0) { return compare; } compare = compareClass(elementType, ((ElementKey<?, ?>) other).elementType); if (compare != 0) { return compare; } return compareClass(datatype, other.datatype); }
/** * Binds an element key to a specific element subclass. This guarantees that * the key on an element will always have exactly that element's type as its * element type, and not some other element type. This makes it possible to * believe an element's key without needing to check the element type when * looking up metadata. */ private static ElementKey<?, ?> bindKey(ElementKey<?, ?> key, Class<? extends Element> type) { Class<?> keyType = key.getElementType(); if (keyType == type) { return key; } return ElementKey.of(key.getId(), key.getDatatype(), type); }
if (transformSource != null) { ElementKey<D, E> transformSourceKey = ElementKey.of( transformSource.getKey().getId(), key.getDatatype(), key.getElementType()); if (transformSourceKey.equals(elemKey)) { this.sourceKey = elemKey; } else {
/** * Get the id of this element. */ public QName getElementId() { return key.getId(); }
/** * Get child element matching the specified key. Will try to adapt the * element to the given key if it is not already an instance of the requested * class. This will fail with an exception if the adaptation was not valid. * * @param <T> the type of element to return * @param childKey the metadata key for the child element to retrieve * @return child element, or {@code null} if none was found * @throws IllegalArgumentException if the key referenced a repeating element */ public <D, T extends Element> T getElement(ElementKey<D, T> childKey) { Element child = getElement(childKey.getId()); if (child == null) { return null; } try { return adapt(childKey, child); } catch (ContentCreationException e) { throw new IllegalArgumentException("Unable to adapt to " + childKey.getElementType(), e); } }
/** * Returns the element value adapted to the key's datatype. * * @param <V> data type of the key. * @param key the element key used to convert the value. * @return typed element value. */ public <V> V getTextValue(ElementKey<V, ?> key) { if (state.value != null) { try { return ObjectConverter.getValue(state.value, key.getDatatype()); } catch (ParseException e) { throw new IllegalArgumentException("Unable to convert value " + e + " to datatype " + key.getDatatype()); } } return null; }
/** * Add a child element with the given ID. This will add the given element to * the end of the collection of elements with the same ID. If you want to * replace any existing elements use {@link #setElement(QName, Element)} * instead. * * @param id the qualified name to use for the child * @param element child element * @return this element for chaining * @throws NullPointerException if element is null. */ public Element addElement(QName id, Element element) { Preconditions.checkNotNull(element); addElement(ElementKey.of(id, element.getElementKey().getDatatype(), element.getClass()), element); return this; }
&& key.equals(source.getElementKey()) && key.getElementType().isInstance(source)) { return key.getElementType().cast(source); Class<? extends E> elementClass = key.getElementType(); try { try {
/** * Checks if the given adaptation is valid. An adaptation is only valid as * part of a composite if the adaptor type is a subtype of the source type. */ private static boolean isValidAdaptation(ElementKey<?, ?> source, ElementKey<?, ?> adaptor) { Class<?> sourceType = source.getElementType(); Class<?> adaptorType = adaptor.getElementType(); if (sourceType == adaptorType) { return false; } return sourceType.isAssignableFrom(adaptorType); }
@Override public boolean equals(Object obj) { if (obj == this) { return true; } if (!(obj instanceof TransformKey)) { return false; } TransformKey other = (TransformKey) obj; if (parent == null) { if (other.parent != null) { return false; } } else if (!parent.equals(other.parent)) { return false; } if (!key.equals(other.key)) { return false; } if (context == null) { if (other.context != null) { return false; } } else if (!context.equals(other.context)) { return false; } return true; }
if (key.getDatatype() == Void.class) { vc.addError(e, CoreErrorDomain.ERR.invalidTextContent.withInternalReason( "Element " + key.getId() + " must not contain text content.")); } else if (key.getDatatype() != Void.class && metadata.isContentRequired()) { vc.addError(e, CoreErrorDomain.ERR.missingTextContent.withInternalReason( "Element " + key.getId() + " must contain a text content value.")); vc.addError(e, CoreErrorDomain.ERR.missingExtensionElement.withInternalReason( "Element must contain a child named " + childKey.getId()));
/** * Returns true if this key matches the given key. A key is considered a * match for another key if the parent and subtypes are matches or subtypes of * the given key's parent and subtype, and the context is a subset of the * matched context. */ boolean matches(TransformKey other) { return (parent == null || parent.matches(other.parent)) && (key.matches(other.key)) && (context == null || context.matches(other.context)); }
@Override public int hashCode() { int hash = key.hashCode(); hash *= 17; if (parent != null) { hash += parent.hashCode(); } hash *= 17; if (context != null) { hash += context.hashCode(); } return hash; }
/** * Returns {@code true} if this key is a match for the given key. This key is * a match for the other key if the other key is also an element key and if * the ID, datatype, and element types all match. */ @Override public boolean matches(MetadataKey<?> other) { if (other == null) { return false; } if (!(other instanceof ElementKey<?, ?>)) { return false; } if (!matchIdAndDatatype(other)) { return false; } return elementType.isAssignableFrom(((ElementKey<?, ?>) other).elementType); }
if (transformSource != null) { ElementKey<D, E> transformSourceKey = ElementKey.of( transformSource.getKey().getId(), key.getDatatype(), key.getElementType()); if (transformSourceKey.equals(elemKey)) { this.sourceKey = elemKey; } else {
/** * Get the id of this element. */ public QName getElementId() { return key.getId(); }
/** * Get child element matching the specified key. Will try to adapt the * element to the given key if it is not already an instance of the requested * class. This will fail with an exception if the adaptation was not valid. * * @param <T> the type of element to return * @param childKey the metadata key for the child element to retrieve * @return child element, or {@code null} if none was found * @throws IllegalArgumentException if the key referenced a repeating element */ public <D, T extends Element> T getElement(ElementKey<D, T> childKey) { Element child = getElement(childKey.getId()); if (child == null) { return null; } try { return adapt(childKey, child); } catch (ContentCreationException e) { throw new IllegalArgumentException("Unable to adapt to " + childKey.getElementType(), e); } }
/** * Returns the element value adapted to the key's datatype. * * @param <V> data type of the key. * @param key the element key used to convert the value. * @return typed element value. */ public <V> V getTextValue(ElementKey<V, ?> key) { if (state.value != null) { try { return ObjectConverter.getValue(state.value, key.getDatatype()); } catch (ParseException e) { throw new IllegalArgumentException("Unable to convert value " + e + " to datatype " + key.getDatatype()); } } return null; }