All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotoolkit.metadata.MetadataStandard Maven / Gradle / Ivy

Go to download

Implementations of metadata derived from ISO 19115. This module provides both an implementation of the metadata interfaces defined in GeoAPI, and a framework for handling those metadata through Java reflection.

There is a newer version: 3.20-geoapi-3.0
Show newest version
/*
 *    Geotoolkit.org - An Open Source Java GIS Toolkit
 *    http://www.geotoolkit.org
 *
 *    (C) 2007-2011, Open Source Geospatial Foundation (OSGeo)
 *    (C) 2009-2011, Geomatys
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License as published by the Free Software Foundation;
 *    version 2.1 of the License.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 */
package org.geotoolkit.metadata;

import java.util.Map;
import java.util.HashMap;
import java.util.Collection;
import java.util.Collections;
import java.util.Locale;
import java.text.ParseException;
import java.util.MissingResourceException;
import javax.swing.tree.TreeNode;
import javax.swing.tree.TreeModel;
import net.jcip.annotations.ThreadSafe;

import org.opengis.annotation.UML;

import org.geotoolkit.resources.Errors;
import org.geotoolkit.util.Strings;
import org.geotoolkit.util.ComparisonMode;
import org.geotoolkit.util.LenientComparable;
import org.geotoolkit.util.logging.Logging;
import org.geotoolkit.util.NullArgumentException;
import org.geotoolkit.util.converter.Classes;
import org.geotoolkit.gui.swing.tree.Trees;
import org.geotoolkit.gui.swing.tree.TreeTableNode;
import org.geotoolkit.gui.swing.tree.DefaultTreeModel;

import static org.geotoolkit.util.ArgumentChecks.ensureNonNull;


/**
 * Enumeration of some metadata standards. A standard is defined by a set of Java interfaces
 * in a specific package or subpackages. For example the {@linkplain #ISO_19115 ISO 19115}
 * standard is defined by GeoAPI interfaces in
 * the {@link org.opengis.metadata} package and subpackages.
 * 

* This class provides some methods operating on metadata instances through * {@linkplain java.lang.reflect Java reflection}. The following rules are * assumed: * *

    *
  • Properties (or metadata attributes) are defined by the collection of {@code get*()} * method with arbitrary return type, or {@code is*()} method with boolean return type, * found in the interface. Getters declared only in the implementation * are ignored.

  • *
  • Every properties are readable.

  • *
  • A property is writable if a {@code set*(...)} method is defined * in the implementation class for the corresponding {@code get*()} method. The * setter doesn't need to be defined in the interface.

  • *
* * An instance of {@code MetadataStandard} is associated to every {@link AbstractMetadata} objects. * The {@code AbstractMetadata} base class usually form the basis of ISO 19115 implementations but * can also be used for other standards. An instance of {@code MetadataStandard} is also associated * with Image I/O {@link org.geotoolkit.image.io.metadata.SpatialMetadataFormat} in order to define * the tree of XML nodes to be associated with raster data. * * @author Martin Desruisseaux (Geomatys) * @version 3.19 * * @since 2.4 * @module */ @ThreadSafe public final class MetadataStandard { /** * An instance working on ISO 19111 standard as defined by * GeoAPI interfaces * in the {@link org.opengis.referencing} package and subpackages. * * @since 2.5 */ public static final MetadataStandard ISO_19111; /** * An instance working on ISO 19115 standard as defined by * GeoAPI interfaces * in the {@link org.opengis.metadata} package and subpackages. */ public static final MetadataStandard ISO_19115; /** * An instance working on ISO 19119 standard as defined by * GeoAPI interfaces * in the {@link org.opengis.service} package and subpackages. * * @since 2.5 */ public static final MetadataStandard ISO_19119; /** * An instance working on ISO 19123 standard as defined by * GeoAPI interfaces * in the {@link org.opengis.coverage} package and subpackages. * * @since 3.06 */ public static final MetadataStandard ISO_19123; static { final String[] prefix = {"Default", "Abstract"}; final String[] acronyms = {"CoordinateSystem", "CS", "CoordinateReferenceSystem", "CRS"}; ISO_19111 = new MetadataStandard("ISO 19111", "org.opengis.referencing.", "org.geotoolkit.referencing.", prefix, acronyms); ISO_19115 = new MetadataStandard("ISO 19115", "org.opengis.metadata.", "org.geotoolkit.metadata.iso.", prefix, null); ISO_19119 = new MetadataStandard("ISO 19119", "org.opengis.service.", null, null, null); ISO_19123 = new MetadataStandard("ISO 19123", "org.opengis.coverage.", null, null, null); } /** * The name, for {@link #toString()} purpose only. */ private final String name; /** * The root packages for metadata interfaces. Must ends with {@code "."}. */ private final String interfacePackage; /** * The root packages for metadata implementations, or {@code null} if none. */ private final String implementationPackage; /** * The prefixes that implementation classes may have, or {@code null} if none. * The most common prefix should be first, since the prefix will be tried in that order. * * @see #getImplementation(Class) */ private final String[] prefix; /** * The acronyms that implementation classes may have, or {@code null} if none. If non-null, * then this array shall contain (full text, acronym) pairs. The full * text shall appear that the end of the class name, otherwise it is not replaced. This is * necessary in order to avoid the replacement of {@code "DefaultCoordinateSystemAxis"} by * {@code "DefaultCSAxis"}. * * @see #getImplementation(Class) * * @since 3.15 */ private final String[] acronyms; /** * Accessors for the specified implementations. */ private final Map,PropertyAccessor> accessors = new HashMap,PropertyAccessor>(); /** * Implementations for a given interface, or {@code null} if none. * If non-null, then this map will be filled as needed. * * @see #getImplementation(Class) */ private final Map,Class> implementations; /** * Shared pool of {@link PropertyTree} instances, once for each thread * (in order to avoid the need for thread synchronization). */ private final ThreadLocal treeBuilders = new ThreadLocal() { @Override protected PropertyTree initialValue() { return new PropertyTree(MetadataStandard.this); } }; /** * Creates a new instance working on implementation of interfaces defined * in the specified package. For the ISO 19115 standard reflected by GeoAPI * interfaces, it should be the {@link org.opengis.metadata} package. * * @param interfacePackage The root package for metadata interfaces. */ public MetadataStandard(String interfacePackage) { this(interfacePackage.substring(interfacePackage.lastIndexOf('.')+1), interfacePackage, null, null, null); } /** * Creates a new instance working on implementation of interfaces defined * in the specified package. * * @param name The name of the standard. * @param interfacePackage The root package for metadata interfaces. * @param implementationPackage The root package for metadata implementations. * @param prefix The prefix of implementation class. This array is not cloned. * @param acronyms An array of (full text, acronyms) pairs. This array is not cloned. */ private MetadataStandard(final String name, String interfacePackage, String implementationPackage, final String[] prefix, final String[] acronyms) { if (!interfacePackage.endsWith(".")) { interfacePackage += '.'; } if (implementationPackage != null) { if (!implementationPackage.endsWith(".")) { implementationPackage += '.'; } implementations = new HashMap,Class>(); if (prefix == null) { throw new NullArgumentException(); } } else { implementations = null; } this.interfacePackage = interfacePackage; this.implementationPackage = implementationPackage; this.acronyms = acronyms; this.prefix = prefix; this.name = name; } /** * Returns the accessor for the specified implementation type. * * @param type The implementation type. * @throws ClassCastException if the specified implementation class do * not implements a metadata interface of the expected package. */ private PropertyAccessor getAccessor(final Class type) throws ClassCastException { final PropertyAccessor accessor = getAccessorOptional(type); if (accessor == null) { throw new ClassCastException(Errors.format( Errors.Keys.UNKNOWN_TYPE_$1, type.getCanonicalName())); } return accessor; } /** * Returns the accessor for the specified implementation type, or {@code null} if none. * * @param type The implementation type. */ final PropertyAccessor getAccessorOptional(final Class type) { synchronized (accessors) { PropertyAccessor accessor = accessors.get(type); if (accessor == null) { final Class standard = getStandardType(type); if (standard != null) { accessor = new PropertyAccessor(type, standard); accessors.put(type, accessor); } } return accessor; } } /** * Returns the metadata interface implemented by the specified implementation. * Only one metadata interface can be implemented. If the given type is already * an interface from the standard, it is returned directly. * * @param type The type of the implementation (could also be the interface type). * @return The single interface, or {@code null} if none where found. */ private Class getStandardType(final Class type) { return PropertyAccessor.getStandardType(type, interfacePackage); } /** * Returns {@code true} if the given type is assignable to a type from this standard. * If this method returns {@code true}, then invoking {@link #getInterface(Class)} is * guaranteed to succeed without throwing an exception. * * @param type The implementation class (can be {@code null}). * @return {@code true} if the given class is an interface of this standard, * or implements an interface of this standard. * * @since 3.03 */ public boolean isMetadata(final Class type) { if (type == null) { return false; } // Checks if the class is an interface from the standard. if (type.getName().startsWith(interfacePackage)) { return true; } // Checks if the class is an implementation of the standard. return getAccessorOptional(type) != null; } /** * Returns the metadata interface implemented by the specified implementation class. * If the given type is already an interface from this standard, then it is returned * unchanged. * * {@note The word "interface" may be taken in a looser sense than the usual Java sense * because if the given type is defined in this standard package, then it is returned * unchanged. The standard package is usually made of interfaces and code lists only, * but this is not verified by this method.} * * @param type The implementation class. * @return The interface implemented by the given implementation class. * @throws ClassCastException if the specified implementation class does * not implement an interface of this standard. * * @see AbstractMetadata#getInterface */ public Class getInterface(final Class type) throws ClassCastException { ensureNonNull("type", type); if (type.getName().startsWith(interfacePackage)) { return type; } return getAccessor(type).type; } /** * Returns the implementation class for the given interface. If no implementation is found, * then the given type is returned unchanged. This method is not public because returning * the type unchanged is not consistent with the usual public API. * * @param type The interface, typically from the {@code org.opengis.metadata} package. * @return The implementation class. */ final Class getImplementation(final Class type) { // We require the type to be an interface in order to exclude // CodeLists, Enums and Exceptions. if (type != null && type.isInterface() && implementations != null) { String name = type.getName(); if (name.startsWith(interfacePackage)) { synchronized (implementations) { Class candidate = implementations.get(type); if (candidate != null) { return (candidate != Void.TYPE) ? candidate : type; } /* * Prepares a buffer with a copy of the class name in which the interface * package has been replaced by the implementation package, and some text * have been replaced by their acronym (if any). */ final StringBuilder buffer = new StringBuilder(implementationPackage) .append(name.substring(interfacePackage.length())); if (acronyms != null) { for (int i=0; i * Example: The following code returns {@code InternationalString.class}. * * {@preformat java * ISO_19115.asTypeMap(Citation.class, ELEMENT_TYPE, UML_IDENTIFIER).get("alternateTitle"); * } * * @param type The interface or implementation class. * @param typeValues Whatever the values should be property types, the element types * (same as property types except for collections) or the declaring class. * @param keyNames Determines the string representation of map keys. * @return The types for the the properties of the given class. * @throws ClassCastException if the specified interface or implementation class does * not extend or implement a metadata interface of the expected package. * * @since 3.03 */ public Map> asTypeMap(Class type, final TypeValuePolicy typeValues, final KeyNamePolicy keyNames) throws ClassCastException { ensureNonNull("type", type); ensureNonNull("typeValues", typeValues); ensureNonNull("keyNames", keyNames); type = getImplementation(type); return new TypeMap(getAccessor(type), typeValues, keyNames); } /** * Returns a view as a {@linkplain Map map} of the property names for the specified metadata type. * The keys are the property names as determined by the list of {@code getFoo()} methods declared * in the {@linkplain #getInterface metadata interface}, or the {@linkplain UML} identifier * associated to those methods. The values are determined by the {@link KeyNamePolicy} argument. *

* Example: The following code returns {@code "alternateTitles"} (note the plural). * * {@preformat java * ISO_19115.asNameMap(Citation.class, JAVABEANS_PROPERTY, UML_IDENTIFIER).get("alternateTitle"); * } * * {@note The KeyNamePolicy type may seem a bit strange for the * valueNames parameter, but this method is used for mapping a * namespace to an other namespace. In each namespace, the names are unique.} * * @param type The interface or implementation class. * @param valueNames Determines the string representation of map values. * @param keyNames Determines the string representation of map keys. * @return The names for the properties of the given class. * @throws ClassCastException if the specified interface or implementation class does * not extend or implement a metadata interface of the expected package. * * @since 3.04 */ public Map asNameMap(Class type, final KeyNamePolicy valueNames, final KeyNamePolicy keyNames) throws ClassCastException { ensureNonNull("type", type); ensureNonNull("typeValues", valueNames); ensureNonNull("keyNames", keyNames); type = getImplementation(type); return new NameMap(getAccessor(type), valueNames, keyNames); } /** * Returns a view as a {@linkplain Map map} of the property descriptions for the specified * metadata type. The keys are the same than {@link #asNameMap asNameMap}, except that only * the keys for which a description is available are declared in the map. The values are * descriptions localized in the given locale if possible, or in the default locale otherwise. *

* Example: The following code returns "Short name or other language name by * which the cited information is known." * * {@preformat java * ISO_19115.asDescriptionMap(Citation.class, Locale.ENGLISH, UML_IDENTIFIER).get("alternateTitle"); * } * * As a special case, the {@code "class"} value can be used for fetching the description * of the class rather than a specific method of that class. * * {@note We could have provided a method without Locale argument and returning * a map with InternationalString values. However the method defined below * is slightly more efficient if the descriptions are going to be asked for more than * one property, because it fetches the ResourceBundle only once.} * * @param type The interface or implementation class. * @param locale Determines the locale of map values. * @param keyNames Determines the string representation of map keys. * @return The descriptions for the properties of the given class, or an empty map * if there is no description for the given class in this metadata standard. * @throws ClassCastException if the specified interface or implementation class does * not extend or implement a metadata interface of the expected package. * * @since 3.05 */ public Map asDescriptionMap(Class type, final Locale locale, final KeyNamePolicy keyNames) throws ClassCastException { ensureNonNull("type", type); ensureNonNull("locale", locale); ensureNonNull("keyNames", keyNames); type = getImplementation(type); try { return new DescriptionMap(getAccessor(type), interfacePackage, locale, keyNames); } catch (MissingResourceException e) { Logging.recoverableException(MetadataStandard.class, "asDescriptionMap", e); return Collections.emptyMap(); } } /** * Returns a view as a {@linkplain Map map} of the restrictions for the specified metadata. * The restrictions are inferred from the {@link org.opengis.annotation.Obligation} and * {@link org.geotoolkit.lang.ValueRange} annotated on the getter methods. *

* The {@code metadata} argument can be either a {@link Class}, or an instance of a * metadata object: *

*

    *
  • If the {@code metadata} argument is a {@link Class}, then this method returns all * restrictions that applied on metadata of the given type.
  • *
  • Otherwise if {@code metadata} is an instance of a metadata object, then this method * returns non-null values only for restrictions that are violated by the given instance. * In this case, the returned map is live: changes to any metadata value * will be immediately reflected in the restriction map.
  • *
* * @param metadata The metadata intance for which to get the restriction that are violated, * or the {@link Class} of a metadata object for listing all restrictions. * @param content Whatever the entries having no restriction or no violation (null value) * should be included in the map. * @param keyNames Determines the string representation of map keys. * @return The restrictions that are violated by the given metadata instance, * or all restrictions if {@code metadata} is a {@link Class}. * @throws ClassCastException if the metadata object doesn't implement a metadata * interface of the expected package. * * @since 3.04 */ public Map asRestrictionMap(Object metadata, final NullValuePolicy content, final KeyNamePolicy keyNames) throws ClassCastException { ensureNonNull("metadata", metadata); ensureNonNull("content", content); ensureNonNull("keyNames", keyNames); final Class type; if (metadata instanceof Class) { type = getImplementation((Class) metadata); metadata = null; } else { type = metadata.getClass(); } return new RestrictionMap(getAccessor(type), metadata, content, keyNames); } /** * Returns a view of the specified metadata object as a {@linkplain Map map}. * The map is backed by the metadata object using Java reflection, so changes * in the underlying metadata object are immediately reflected in the map. *

* The content of the {@linkplain Map#keySet() key set} is determined by the arguments: * {@code metadata} determines the set of keys, {@code content} determines whatever the * keys for entries having a null value or an empty collection should be included, and * {@code keyNames} determines their {@code String} representations. *

* The map supports the {@link Map#put put} operations if the underlying metadata object * contains {@code setFoo(...)} methods. The keys are case-insensitive and can be either * the javabeans property name, or the UML identifier. * * @param metadata The metadata object to view as a map. * @param content Whatever the entries having null value or empty collection should be * included in the map. The default is {@link NullValuePolicy#NON_EMPTY NON_EMPTY}. * @param keyNames Determines the string representation of map keys. The default is * {@link KeyNamePolicy#JAVABEANS_PROPERTY JAVABEANS_PROPERTY}. * @return A map view over the metadata object. * @throws ClassCastException if the metadata object doesn't implement a metadata * interface of the expected package. * * @since 3.03 */ public Map asMap(final Object metadata, final NullValuePolicy content, final KeyNamePolicy keyNames) throws ClassCastException { ensureNonNull("metadata", metadata); ensureNonNull("content", content); ensureNonNull("keyNames", keyNames); return new PropertyMap(metadata, getAccessor(metadata.getClass()), content, keyNames); } /** * Returns a view as a {@linkplain Map map} of the specified metadata object. * The map is backed by the metadata object using Java reflection, so changes * in the underlying metadata object are immediately reflected in the map. * The keys are the property names as determined by the list of {@code getFoo()} * methods declared in the {@linkplain #getInterface metadata interface}, and * only the entries with a non-null or non-{@linkplain Collection#isEmpty empty} * value are listed. *

* The map supports the {@link Map#put put} operations if the underlying metadata * object contains {@code setFoo(...)} methods. The keys are case-insensitive and * can be either the javabeans property name, or the UML identifier. * * @param metadata The metadata object to view as a map. * @return A map view over the metadata object. * @throws ClassCastException if the metadata object doesn't implement a metadata * interface of the expected package. * * @see AbstractMetadata#asMap() */ public Map asMap(final Object metadata) throws ClassCastException { return asMap(metadata, NullValuePolicy.NON_EMPTY, KeyNamePolicy.JAVABEANS_PROPERTY); } /** * Returns a view of the specified metadata as a tree table. Note that while {@link TreeTableNode} * is defined in a {@link org.geotoolkit.gui.swing} sub-package, it can be seen as a data structure * independent of Swing. It will not force class loading of Swing framework. *

* In current implementation, the tree is not live (i.e. changes in metadata are not * reflected in the tree). However it may be improved in a future Geotk implementation. * * @param metadata The metadata object to formats as a tree table. * @return A tree table representation of the specified metadata. * @throws ClassCastException if the metadata object doesn't implement a metadata * interface of the expected package. * * @see AbstractMetadata#asTreeTable() * * @since 3.19 */ public TreeTableNode asTreeTable(final Object metadata) throws ClassCastException { return treeBuilders.get().asTreeTable(metadata); } /** * Returns a view of the specified metadata as a tree. Note that while {@link TreeModel} * is defined in the {@link javax.swing.tree} package, it can be seen as a data structure * independent of Swing. It will not force class loading of Swing framework. *

* In current implementation, the tree is not live (i.e. changes in metadata are not * reflected in the tree). However it may be improved in a future Geotk implementation. * * @param metadata The metadata object to formats as a tree. * @return A tree representation of the specified metadata. * @throws ClassCastException if the metadata object doesn't implement a metadata * interface of the expected package. * * @see AbstractMetadata#asTree() */ public TreeModel asTree(final Object metadata) throws ClassCastException { final PropertyTree builder = treeBuilders.get(); return new DefaultTreeModel(builder.asTree(metadata), true); } /** * Fetches values from every nodes of the given tree except the root, and puts them in * the given metadata object. The value of the root node is ignored (it is typically * just the name of the metadata class). *

* If the given metadata object already contains property values, then the parsing will be * merged with the existing values: attributes not defined in the tree will be left unchanged, * and collections will be augmented with new entries without change in the previously existing * entries. *

* This method can parse the tree created by {@link #asTree(Object)}. The current implementation * expects the {@linkplain TreeModel#getRoot tree root} to be an instance of {@link TreeNode}. * * @param root The tree from which to fetch the values. * @param metadata The metadata where to store the values. * @throws ParseException If a value can not be stored in the given metadata object. */ final void parse(final TreeModel tree, final Object metadata) throws ParseException { treeBuilders.get().parse((TreeNode) tree.getRoot(), metadata); } /** * Returns {@code true} if this metadata is modifiable. This method is not public because it * uses heuristic rules. In case of doubt, this method conservatively returns {@code true}. * * @throws ClassCastException if the specified implementation class do * not implements a metadata interface of the expected package. * * @see ModifiableMetadata#isModifiable */ final boolean isModifiable(final Class implementation) throws ClassCastException { return getAccessor(implementation).isModifiable(); } /** * Replaces every properties in the specified metadata by their * {@linkplain ModifiableMetadata#unmodifiable unmodifiable variant. * * @throws ClassCastException if the specified implementation class do * not implements a metadata interface of the expected package. * * @see ModifiableMetadata#freeze() */ final void freeze(final Object metadata) throws ClassCastException { getAccessor(metadata.getClass()).freeze(metadata); } /** * Copies all metadata from source to target. The source must implements the same * metadata interface than the target. * * @param source The metadata to copy. * @param target The target metadata. * @param skipNulls If {@code true}, only non-null values will be copied. * @throws ClassCastException if the source or target object don't * implements a metadata interface of the expected package. * @throws UnmodifiableMetadataException if the target metadata is unmodifiable, * or if at least one setter method was required but not found. * * @see ModifiableMetadata#clone */ public void shallowCopy(final Object source, final Object target, final boolean skipNulls) throws ClassCastException, UnmodifiableMetadataException { ensureNonNull("target", target); final PropertyAccessor accessor = getAccessor(target.getClass()); if (!accessor.type.isInstance(source)) { ensureNonNull("source", source); throw new ClassCastException(Errors.format(Errors.Keys.ILLEGAL_CLASS_$3, "source", source.getClass(), accessor.type)); } if (!accessor.shallowCopy(source, target, skipNulls)) { throw new UnmodifiableMetadataException(Errors.format(Errors.Keys.UNMODIFIABLE_METADATA)); } } /** * Compares the two specified metadata objects. The comparison is shallow, * i.e. all metadata attributes are compared using the * {@link LenientComparable#equals(Object, ComparisonMode)} method if possible, or the * {@link Object#equals(Object)} method otherwise, without explicit recursive call to * this {@code shallowEquals(...)} method for child metadata. *

* This method can optionally excludes null values from the comparison. In metadata, * null value often means "don't know", so in some occasion we want to consider two * metadata as different only if a property value is know for sure to be different. *

* The first arguments must be an implementation of a metadata interface, otherwise an * exception will be thrown. The two arguments do not need to be the same implementation * however. * * @param metadata1 The first metadata object to compare. * @param metadata2 The second metadata object to compare. * @param mode The strictness level of the comparison. * @param skipNulls If {@code true}, only non-null values will be compared. * @return {@code true} if the given metadata objects are equals. * @throws ClassCastException if at least one metadata object don't * implements a metadata interface of the expected package. * * @see AbstractMetadata#equals(Object, ComparisonMode) */ public boolean shallowEquals(final Object metadata1, final Object metadata2, final ComparisonMode mode, final boolean skipNulls) throws ClassCastException { if (metadata1 == metadata2) { return true; } if (metadata1 == null || metadata2 == null) { return false; } final PropertyAccessor accessor = getAccessor(metadata1.getClass()); if (accessor.type != getStandardType(metadata2.getClass())) { return false; } return accessor.shallowEquals(metadata1, metadata2, mode, skipNulls); } /** * Computes a hash code for the specified metadata. The hash code is defined as the * sum of hash code values of all non-null properties. This is the same contract than * {@link java.util.Set#hashCode} and ensure that the hash code value is insensitive * to the ordering of properties. * * @param metadata The metadata object to compute hash code. * @return A hash code value for the specified metadata. * @throws ClassCastException if the metadata object doesn't implement a metadata * interface of the expected package. * * @see AbstractMetadata#hashCode */ public int hashCode(final Object metadata) throws ClassCastException { return getAccessor(metadata.getClass()).hashCode(metadata); } /** * Returns a string representation of the specified metadata. * * @param metadata The metadata object to formats as a string. * @return A string representation of the specified metadata. * @throws ClassCastException if the metadata object doesn't implement a metadata * interface of the expected package. * * @see AbstractMetadata#toString */ public String toString(final Object metadata) throws ClassCastException { return Trees.toString(asTreeTable(metadata)); } /** * Returns a string representation of this metadata standard. This is * for debugging purpose only and may change in any future version. */ @Override public String toString() { return Classes.getShortClassName(this) + '[' + name + ']'; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy