Remove extended metadata from ClassMeta/BeanMeta/BeanPropertyMeta.
diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanMeta.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanMeta.java
index 4e035ec..4c2b721 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanMeta.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanMeta.java
@@ -19,7 +19,7 @@
  * Metadata on beans specific to the RDF serializers and parsers pulled from the {@link Rdf @Rdf} annotation on the

  * class.

  */

-public class RdfBeanMeta extends BeanMetaExtended {

+public class RdfBeanMeta extends ExtendedBeanMeta {

 

 	// RDF related fields

 	private final BeanPropertyMeta beanUriProperty;    // Bean property that identifies the URI of the bean.

@@ -28,13 +28,14 @@
 	 * Constructor.

 	 *

 	 * @param beanMeta The metadata on the bean that this metadata applies to.

+	 * @param rdfMetaProvider RDF metadata provider (for finding information about other artifacts).

 	 */

-	public RdfBeanMeta(BeanMeta<?> beanMeta) {

+	public RdfBeanMeta(BeanMeta<?> beanMeta, RdfMetaProvider rdfMetaProvider) {

 		super(beanMeta);

 

 		BeanPropertyMeta t_beanUriProperty = null;

 		for (BeanPropertyMeta p : beanMeta.getPropertyMetas()) {

-			RdfBeanPropertyMeta bpm = p.getExtendedMeta(RdfBeanPropertyMeta.class);

+			RdfBeanPropertyMeta bpm = rdfMetaProvider.getRdfBeanPropertyMeta(p);

 			if (bpm.isBeanUri())

 				t_beanUriProperty = p;

 		}

diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
index 6fdfb63..ec1eaff 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfBeanPropertyMeta.java
@@ -22,7 +22,7 @@
  * Metadata on bean properties specific to the RDF serializers and parsers pulled from the {@link Rdf @Rdf} annotation

  * on the bean property.

  */

-public class RdfBeanPropertyMeta extends BeanPropertyMetaExtended {

+public class RdfBeanPropertyMeta extends ExtendedBeanPropertyMeta {

 

 	/**

 	 * Default instance.

@@ -38,8 +38,9 @@
 	 * Constructor.

 	 *

 	 * @param bpm The metadata of the bean property of this additional metadata.

+	 * @param rdfMetaProvider RDF metadata provider (for finding information about other artifacts).

 	 */

-	public RdfBeanPropertyMeta(BeanPropertyMeta bpm) {

+	public RdfBeanPropertyMeta(BeanPropertyMeta bpm, RdfMetaProvider rdfMetaProvider) {

 		super(bpm);

 

 		List<Rdf> rdfs = bpm.findAnnotations(Rdf.class);

diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfClassMeta.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfClassMeta.java
index 9474a96..ac1fe64 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfClassMeta.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfClassMeta.java
@@ -23,7 +23,7 @@
  * Metadata on classes specific to the RDF serializers and parsers pulled from the {@link Rdf @Rdf} annotation on the

  * class.

  */

-public class RdfClassMeta extends ClassMetaExtended {

+public class RdfClassMeta extends ExtendedClassMeta {

 

 	private final Rdf rdf;

 	private final RdfCollectionFormat collectionFormat;

@@ -33,8 +33,9 @@
 	 * Constructor.

 	 *

 	 * @param cm The class that this annotation is defined on.

+	 * @param rdfMetaProvider RDF metadata provider (for finding information about other artifacts).

 	 */

-	public RdfClassMeta(ClassMeta<?> cm) {

+	public RdfClassMeta(ClassMeta<?> cm, RdfMetaProvider rdfMetaProvider) {

 		super(cm);

 		ClassInfo ci = cm.getInfo();

 		this.rdf = ci.getAnnotation(Rdf.class);

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMetaExtended.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfMetaProvider.java
similarity index 63%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMetaExtended.java
copy to juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfMetaProvider.java
index 43362f2..7f598c7 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMetaExtended.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfMetaProvider.java
@@ -10,35 +10,37 @@
 // * "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.apache.juneau;
+package org.apache.juneau.jena;
+
+import org.apache.juneau.*;
+import org.apache.juneau.xml.*;
 
 /**
- * Defines extended language-specific metadata associated with a bean property.
- *
- * <p>
- * Serializers and parsers can implement their own language-specific metadata on a bean property and retrieve
- * the metadata using the {@link BeanPropertyMeta#getExtendedMeta(Class)} method.
+ * Interface for providing access to {@link RdfClassMeta}, {@link RdfBeanMeta}, and {@link RdfBeanPropertyMeta} objects.
  */
-public class BeanPropertyMetaExtended {
-
-	private final BeanPropertyMeta bpm;
+public interface RdfMetaProvider extends XmlMetaProvider {
 
 	/**
-	 * Constructor.
+	 * Returns the language-specific metadata on the specified class.
 	 *
-	 * @param bpm The metadata of the bean property we're extending.
-	 * @throws BeanRuntimeException If any error occurred trying to construct the metadata.
+	 * @param cm The class to return the metadata on.
+	 * @return The metadata.
 	 */
-	public BeanPropertyMetaExtended(BeanPropertyMeta bpm) throws BeanRuntimeException {
-		this.bpm = bpm;
-	}
+	RdfClassMeta getRdfClassMeta(ClassMeta<?> cm);
 
 	/**
-	 * Returns the bean property metadata that was passed into the constructor.
+	 * Returns the language-specific metadata on the specified bean.
 	 *
-	 * @return The bean property metadata that was passed into the constructor.
+	 * @param bm The bean to return the metadata on.
+	 * @return The metadata.
 	 */
-	protected BeanPropertyMeta getBeanPropertyMeta() {
-		return bpm;
-	}
+	RdfBeanMeta getRdfBeanMeta(BeanMeta<?> bm);
+
+	/**
+	 * Returns the language-specific metadata on the specified bean property.
+	 *
+	 * @param bpm The bean property to return the metadata on.
+	 * @return The metadata.
+	 */
+	RdfBeanPropertyMeta getRdfBeanPropertyMeta(BeanPropertyMeta bpm);
 }
diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParser.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParser.java
index f647de4..a2dc6f3 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParser.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParser.java
@@ -15,6 +15,7 @@
 import static org.apache.juneau.internal.CollectionUtils.*;

 

 import java.util.*;

+import java.util.concurrent.*;

 

 import org.apache.juneau.*;

 import org.apache.juneau.annotation.*;

@@ -43,7 +44,7 @@
  * </ul>

  */

 @ConfigurableContext(prefixes={RdfCommon.PREFIX,RdfParser.PREFIX})

-public class RdfParser extends ReaderParser implements RdfCommon {

+public class RdfParser extends ReaderParser implements RdfCommon, RdfMetaProvider {

 

 	private static final Namespace

 		DEFAULT_JUNEAU_NS = Namespace.create("j", "http://www.apache.org/juneau/"),

@@ -105,6 +106,14 @@
 

 	final Map<String,Object> jenaProperties;

 

+	private final Map<ClassMeta<?>,RdfClassMeta> rdfClassMetas = new ConcurrentHashMap<>();

+	private final Map<BeanMeta<?>,RdfBeanMeta> rdfBeanMetas = new ConcurrentHashMap<>();

+	private final Map<BeanPropertyMeta,RdfBeanPropertyMeta> rdfBeanPropertyMetas = new ConcurrentHashMap<>();

+

+	private final Map<ClassMeta<?>,XmlClassMeta> xmlClassMetas = new ConcurrentHashMap<>();

+	private final Map<BeanMeta<?>,XmlBeanMeta> xmlBeanMetas = new ConcurrentHashMap<>();

+	private final Map<BeanPropertyMeta,XmlBeanPropertyMeta> xmlBeanPropertyMetas = new ConcurrentHashMap<>();

+

 	/**

 	 * Constructor.

 	 *

@@ -168,6 +177,70 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	@Override /* RdfMetaProvider */

+	public RdfClassMeta getRdfClassMeta(ClassMeta<?> cm) {

+		RdfClassMeta m = rdfClassMetas.get(cm);

+		if (m == null) {

+			m = new RdfClassMeta(cm, this);

+			rdfClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	@Override /* RdfMetaProvider */

+	public RdfBeanMeta getRdfBeanMeta(BeanMeta<?> bm) {

+		RdfBeanMeta m = rdfBeanMetas.get(bm);

+		if (m == null) {

+			m = new RdfBeanMeta(bm, this);

+			rdfBeanMetas.put(bm, m);

+		}

+		return m;

+	}

+

+	@Override /* RdfMetaProvider */

+	public RdfBeanPropertyMeta getRdfBeanPropertyMeta(BeanPropertyMeta bpm) {

+		RdfBeanPropertyMeta m = rdfBeanPropertyMetas.get(bpm);

+		if (m == null) {

+			m = new RdfBeanPropertyMeta(bpm.getDelegateFor(), this);

+			rdfBeanPropertyMetas.put(bpm, m);

+		}

+		return m;

+	}

+

+	@Override /* XmlMetaProvider */

+	public XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) {

+		XmlClassMeta m = xmlClassMetas.get(cm);

+		if (m == null) {

+			m = new XmlClassMeta(cm, this);

+			xmlClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	@Override /* XmlMetaProvider */

+	public XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) {

+		XmlBeanMeta m = xmlBeanMetas.get(bm);

+		if (m == null) {

+			m = new XmlBeanMeta(bm, this);

+			xmlBeanMetas.put(bm, m);

+		}

+		return m;

+	}

+

+	@Override /* XmlMetaProvider */

+	public XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		XmlBeanPropertyMeta m = xmlBeanPropertyMetas.get(bpm);

+		if (m == null) {

+			m = new XmlBeanPropertyMeta(bpm.getDelegateFor(), this);

+			xmlBeanPropertyMetas.put(bpm, m);

+		}

+		return m;

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Common properties

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
index 31b3eed..3d2a171 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfParserSession.java
@@ -168,7 +168,7 @@
 

 	private <T> BeanMap<T> parseIntoBeanMap(Resource r2, BeanMap<T> m) throws IOException, ParseException, ExecutableException {

 		BeanMeta<T> bm = m.getMeta();

-		RdfBeanMeta rbm = bm.getExtendedMeta(RdfBeanMeta.class);

+		RdfBeanMeta rbm = getRdfBeanMeta(bm);

 		if (rbm.hasBeanUri() && r2.getURI() != null)

 			rbm.getBeanUriProperty().set(m, null, r2.getURI());

 		for (StmtIterator i = r2.listProperties(); i.hasNext();) {

@@ -199,7 +199,7 @@
 	}

 

 	private boolean isMultiValuedCollections(BeanPropertyMeta pMeta) {

-		RdfBeanPropertyMeta bpRdf = (pMeta == null ? RdfBeanPropertyMeta.DEFAULT : pMeta.getExtendedMeta(RdfBeanPropertyMeta.class));

+		RdfBeanPropertyMeta bpRdf = (pMeta == null ? RdfBeanPropertyMeta.DEFAULT : getRdfBeanPropertyMeta(pMeta));

 

 		if (bpRdf.getCollectionFormat() != RdfCollectionFormat.DEFAULT)

 			return bpRdf.getCollectionFormat() == RdfCollectionFormat.MULTI_VALUED;

@@ -516,6 +516,50 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	/**

+	 * Returns the language-specific metadata on the specified class.

+	 *

+	 * @param cm The class to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected RdfClassMeta getRdfClassMeta(ClassMeta<?> cm) {

+		return ctx.getRdfClassMeta(cm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean.

+	 *

+	 * @param bm The bean to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected RdfBeanMeta getRdfBeanMeta(BeanMeta<?> bm) {

+		return ctx.getRdfBeanMeta(bm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean property.

+	 *

+	 * @param bpm The bean property to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected RdfBeanPropertyMeta getRdfBeanPropertyMeta(BeanPropertyMeta bpm) {

+		return ctx.getRdfBeanPropertyMeta(bpm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean property.

+	 *

+	 * @param bpm The bean property to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		return ctx.getXmlBeanPropertyMeta(bpm);

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
index 08aa592..86fe318 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializer.java
@@ -15,6 +15,7 @@
 import static org.apache.juneau.internal.CollectionUtils.*;

 

 import java.util.*;

+import java.util.concurrent.*;

 

 import org.apache.juneau.*;

 import org.apache.juneau.annotation.*;

@@ -42,7 +43,7 @@
  * </ul>

  */

 @ConfigurableContext(prefixes={RdfCommon.PREFIX,RdfSerializer.PREFIX})

-public class RdfSerializer extends WriterSerializer implements RdfCommon {

+public class RdfSerializer extends WriterSerializer implements RdfCommon, RdfMetaProvider {

 

 	private static final Namespace

 		DEFAULT_JUNEAU_NS = Namespace.create("j", "http://www.apache.org/juneau/"),

@@ -215,6 +216,14 @@
 	final Map<String,Object> jenaProperties;

 	final Namespace[] namespaces;

 

+	private final Map<ClassMeta<?>,RdfClassMeta> rdfClassMetas = new ConcurrentHashMap<>();

+	private final Map<BeanMeta<?>,RdfBeanMeta> rdfBeanMetas = new ConcurrentHashMap<>();

+	private final Map<BeanPropertyMeta,RdfBeanPropertyMeta> rdfBeanPropertyMetas = new ConcurrentHashMap<>();

+

+	private final Map<ClassMeta<?>,XmlClassMeta> xmlClassMetas = new ConcurrentHashMap<>();

+	private final Map<BeanMeta<?>,XmlBeanMeta> xmlBeanMetas = new ConcurrentHashMap<>();

+	private final Map<BeanPropertyMeta,XmlBeanPropertyMeta> xmlBeanPropertyMetas = new ConcurrentHashMap<>();

+

 	/**

 	 * Constructor.

 	 *

@@ -305,6 +314,70 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	@Override /* RdfMetaProvider */

+	public RdfClassMeta getRdfClassMeta(ClassMeta<?> cm) {

+		RdfClassMeta m = rdfClassMetas.get(cm);

+		if (m == null) {

+			m = new RdfClassMeta(cm, this);

+			rdfClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	@Override /* RdfMetaProvider */

+	public RdfBeanMeta getRdfBeanMeta(BeanMeta<?> bm) {

+		RdfBeanMeta m = rdfBeanMetas.get(bm);

+		if (m == null) {

+			m = new RdfBeanMeta(bm, this);

+			rdfBeanMetas.put(bm, m);

+		}

+		return m;

+	}

+

+	@Override /* RdfMetaProvider */

+	public RdfBeanPropertyMeta getRdfBeanPropertyMeta(BeanPropertyMeta bpm) {

+		RdfBeanPropertyMeta m = rdfBeanPropertyMetas.get(bpm);

+		if (m == null) {

+			m = new RdfBeanPropertyMeta(bpm.getDelegateFor(), this);

+			rdfBeanPropertyMetas.put(bpm, m);

+		}

+		return m;

+	}

+

+	@Override /* XmlMetaProvider */

+	public XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) {

+		XmlClassMeta m = xmlClassMetas.get(cm);

+		if (m == null) {

+			m = new XmlClassMeta(cm, this);

+			xmlClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	@Override /* XmlMetaProvider */

+	public XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) {

+		XmlBeanMeta m = xmlBeanMetas.get(bm);

+		if (m == null) {

+			m = new XmlBeanMeta(bm, this);

+			xmlBeanMetas.put(bm, m);

+		}

+		return m;

+	}

+

+	@Override /* XmlMetaProvider */

+	public XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		XmlBeanPropertyMeta m = xmlBeanPropertyMetas.get(bpm);

+		if (m == null) {

+			m = new XmlBeanPropertyMeta(bpm.getDelegateFor(), this);

+			xmlBeanPropertyMetas.put(bpm, m);

+		}

+		return m;

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Common properties

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
index 2036305..dcc665f 100644
--- a/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
+++ b/juneau-core/juneau-marshall-rdf/src/main/java/org/apache/juneau/jena/RdfSerializerSession.java
@@ -223,7 +223,7 @@
 			if (o instanceof BeanMap) {

 				BeanMap bm = (BeanMap)o;

 				Object uri = null;

-				RdfBeanMeta rbm = bRdf(bm.getMeta());

+				RdfBeanMeta rbm = getRdfBeanMeta(bm.getMeta());

 				if (rbm.hasBeanUri())

 					uri = rbm.getBeanUriProperty().get(bm, null);

 				String uri2 = getUri(uri, null);

@@ -238,7 +238,7 @@
 		} else if (sType.isBean()) {

 			BeanMap bm = toBeanMap(o);

 			Object uri = null;

-			RdfBeanMeta rbm = bRdf(bm.getMeta());

+			RdfBeanMeta rbm = getRdfBeanMeta(bm.getMeta());

 			if (rbm.hasBeanUri())

 				uri = rbm.getBeanUriProperty().get(bm, null);

 			String uri2 = getUri(uri, null);

@@ -249,8 +249,8 @@
 

 			Collection c = sort(sType.isCollection() ? (Collection)o : toList(sType.getInnerClass(), o));

 			RdfCollectionFormat f = getCollectionFormat();

-			RdfClassMeta cRdf = cRdf(sType);

-			RdfBeanPropertyMeta bpRdf = bpRdf(bpm);

+			RdfClassMeta cRdf = getRdfClassMeta(sType);

+			RdfBeanPropertyMeta bpRdf = getRdfBeanPropertyMeta(bpm);

 

 			if (cRdf.getCollectionFormat() != RdfCollectionFormat.DEFAULT)

 				f = cRdf.getCollectionFormat();

@@ -315,8 +315,8 @@
 

 			BeanPropertyMeta bpMeta = bpv.getMeta();

 			ClassMeta<?> cMeta = bpMeta.getClassMeta();

-			RdfBeanPropertyMeta bpRdf = bpRdf(bpMeta);

-			XmlBeanPropertyMeta bpXml = bpXml(bpMeta);

+			RdfBeanPropertyMeta bpRdf = getRdfBeanPropertyMeta(bpMeta);

+			XmlBeanPropertyMeta bpXml = getXmlBeanPropertyMeta(bpMeta);

 

 			if (bpRdf.isBeanUri())

 				continue;

@@ -369,8 +369,8 @@
 			BeanPropertyMeta bpm, String attrName, Resource parentResource) throws IOException, SerializeException {

 

 		ClassMeta<?> elementType = sType.getElementType();

-		RdfBeanPropertyMeta bpRdf = bpRdf(bpm);

-		XmlBeanPropertyMeta bpXml = bpXml(bpm);

+		RdfBeanPropertyMeta bpRdf = getRdfBeanPropertyMeta(bpm);

+		XmlBeanPropertyMeta bpXml = getXmlBeanPropertyMeta(bpm);

 

 		for (Object e : c) {

 			Namespace ns = bpRdf.getNamespace();

@@ -386,22 +386,7 @@
 		}

 	}

 

-	private static RdfClassMeta cRdf(ClassMeta<?> cm) {

-		return cm.getExtendedMeta(RdfClassMeta.class);

-	}

-

-	private static XmlBeanPropertyMeta bpXml(BeanPropertyMeta pMeta) {

-		return pMeta == null ? XmlBeanPropertyMeta.DEFAULT : pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);

-	}

-

-	private static RdfBeanPropertyMeta bpRdf(BeanPropertyMeta pMeta) {

-		return pMeta == null ? RdfBeanPropertyMeta.DEFAULT : pMeta.getExtendedMeta(RdfBeanPropertyMeta.class);

-	}

-

-	private static RdfBeanMeta bRdf(BeanMeta bm) {

-		return (RdfBeanMeta)bm.getExtendedMeta(RdfBeanMeta.class);

-	}

-

+	

 	//-----------------------------------------------------------------------------------------------------------------

 	// Common properties

 	//-----------------------------------------------------------------------------------------------------------------

@@ -551,6 +536,50 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	/**

+	 * Returns the language-specific metadata on the specified class.

+	 *

+	 * @param cm The class to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected RdfClassMeta getRdfClassMeta(ClassMeta<?> cm) {

+		return ctx.getRdfClassMeta(cm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean.

+	 *

+	 * @param bm The bean to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected RdfBeanMeta getRdfBeanMeta(BeanMeta<?> bm) {

+		return ctx.getRdfBeanMeta(bm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean property.

+	 *

+	 * @param bpm The bean property to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected RdfBeanPropertyMeta getRdfBeanPropertyMeta(BeanPropertyMeta bpm) {

+		return bpm == null ? RdfBeanPropertyMeta.DEFAULT : ctx.getRdfBeanPropertyMeta(bpm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean property.

+	 *

+	 * @param bpm The bean property to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		return bpm == null ? XmlBeanPropertyMeta.DEFAULT : ctx.getXmlBeanPropertyMeta(bpm);

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
index 3e7fd31..3b83da0 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMeta.java
@@ -27,7 +27,6 @@
 import org.apache.juneau.annotation.*;

 import org.apache.juneau.reflect.*;

 import org.apache.juneau.transform.*;

-import org.apache.juneau.utils.*;

 

 /**

  * Encapsulates all access to the properties of a bean class (like a souped-up {@link java.beans.BeanInfo}).

@@ -92,8 +91,6 @@
 	/** For beans with constructors with Beanc annotation, this is the list of constructor arg properties. */

 	protected final String[] constructorArgs;

 

-	private final MetadataMap extMeta;  // Extended metadata

-

 	// Other fields

 	final String typePropertyName;                         // "_type" property actual name.

 	private final BeanPropertyMeta typeProperty;           // "_type" mock bean property.

@@ -129,7 +126,6 @@
 		this.typeVarImpls = unmodifiableMap(b.typeVarImpls);

 		this.constructor = b.constructor;

 		this.constructorArgs = b.constructorArgs;

-		this.extMeta = b.extMeta;

 		this.beanRegistry = b.beanRegistry;

 		this.typePropertyName = b.typePropertyName;

 		this.typeProperty = BeanPropertyMeta.builder(this, typePropertyName).canRead().canWrite().rawMetaType(ctx.string()).beanRegistry(beanRegistry).build();

@@ -150,7 +146,6 @@
 		Map<Class<?>,Class<?>[]> typeVarImpls;

 		ConstructorInfo constructor;

 		String[] constructorArgs = new String[0];

-		MetadataMap extMeta = new MetadataMap();

 		PropertyNamer propertyNamer;

 		BeanRegistry beanRegistry;

 		String dictionaryName, typePropertyName;

@@ -832,16 +827,6 @@
 	}

 

 	/**

-	 * Returns the language-specified extended metadata on this bean class.

-	 *

-	 * @param metaDataClass The name of the metadata class to create.

-	 * @return Extended metadata on this bean class.  Never <jk>null</jk>.

-	 */

-	public <M extends BeanMetaExtended> M getExtendedMeta(Class<M> metaDataClass) {

-		return extMeta.get(metaDataClass, this);

-	}

-

-	/**

 	 * Returns metadata about the specified property.

 	 *

 	 * @param name The name of the property on this bean.

@@ -968,4 +953,17 @@
 		sb.append('}');

 		return sb.toString();

 	}

+

+	@Override /* Object */

+	public int hashCode() {

+		return classMeta.hashCode();

+	}

+

+	@Override /* Object */

+	public boolean equals(Object o) {

+		if (o == null || ! (o instanceof BeanMeta))

+			return false;

+		BeanMeta<?> o2 = (BeanMeta<?>)o;

+		return o2.classMeta.equals(this.classMeta);

+	}

 }

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
index bf4678b..ca2da56 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMeta.java
@@ -30,7 +30,6 @@
 import org.apache.juneau.serializer.*;

 import org.apache.juneau.transform.*;

 import org.apache.juneau.transforms.*;

-import org.apache.juneau.utils.*;

 

 /**

  * Contains metadata about a bean property.

@@ -64,12 +63,12 @@
 	private final String[] properties;                        // The value of the @Beanp(properties) annotation.

 	private final PojoSwap swap;                              // PojoSwap defined only via @Beanp annotation.

 

-	private final MetadataMap extMeta;                        // Extended metadata

 	private final BeanRegistry beanRegistry;

 

 	private final Object overrideValue;                       // The bean property value (if it's an overridden delegate).

 	private final BeanPropertyMeta delegateFor;               // The bean property that this meta is a delegate for.

 	private final boolean canRead, canWrite, readOnly, writeOnly;

+	private final int hashCode;

 

 	/**

 	 * Creates a builder for {@link #BeanPropertyMeta} objects.

@@ -98,7 +97,6 @@
 		BeanRegistry beanRegistry;

 		Object overrideValue;

 		BeanPropertyMeta delegateFor;

-		MetadataMap extMeta = new MetadataMap();

 		boolean canRead, canWrite, readOnly, writeOnly;

 

 		Builder(BeanMeta<?> beanMeta, String name) {

@@ -434,13 +432,13 @@
 		this.beanRegistry = b.beanRegistry;

 		this.overrideValue = b.overrideValue;

 		this.delegateFor = b.delegateFor;

-		this.extMeta = b.extMeta;

 		this.isDyna = b.isDyna;

 		this.isDynaGetterMap = b.isDynaGetterMap;

 		this.canRead = b.canRead;

 		this.canWrite = b.canWrite;

 		this.readOnly = b.readOnly;

 		this.writeOnly = b.writeOnly;

+		this.hashCode = HashCode.create().add(beanMeta.hashCode()).add(name == null ? 0 : name.hashCode()).get();

 	}

 

 	/**

@@ -566,15 +564,12 @@
 	}

 

 	/**

-	 * Returns the language-specified extended metadata on this bean property.

+	 * Returns the metadata on the property that this metadata is a delegate for.

 	 *

-	 * @param c The name of the metadata class to create.

-	 * @return Extended metadata on this bean property.  Never <jk>null</jk>.

+	 * @return the metadata on the property that this metadata is a delegate for, or this object if it's not a delegate.

 	 */

-	public <M extends BeanPropertyMetaExtended> M getExtendedMeta(Class<M> c) {

-		if (delegateFor != null)

-			return delegateFor.getExtendedMeta(c);

-		return extMeta.get(c, this);

+	public BeanPropertyMeta getDelegateFor() {

+		return delegateFor != null ? delegateFor : this;

 	}

 

 	/**

@@ -1294,4 +1289,17 @@
 	protected boolean isWriteOnly() {

 		return writeOnly;

 	}

+

+	@Override /* Object */

+	public int hashCode() {

+		return hashCode;

+	}

+

+	@Override /* Object */

+	public boolean equals(Object o) {

+		if (o == null || ! (o instanceof BeanPropertyMeta))

+			return false;

+		BeanPropertyMeta o2 = (BeanPropertyMeta)o;

+		return o2.beanMeta.equals(this.beanMeta) && isEquals(o2.name, this.name);

+	}

 }
\ No newline at end of file
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
index fe532b0..c78437b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMeta.java
@@ -33,7 +33,6 @@
 import org.apache.juneau.json.*;

 import org.apache.juneau.reflect.*;

 import org.apache.juneau.transform.*;

-import org.apache.juneau.utils.*;

 

 /**

  * A wrapper class around the {@link Class} object that provides cached information about that class.

@@ -93,7 +92,6 @@
 	private final PojoSwap<T,?>[] pojoSwaps;                // The object POJO swaps associated with this bean (if it has any).

 	private final BeanFilter beanFilter;                    // The bean filter associated with this bean (if it has one).

 	private final BuilderSwap<T,?> builderSwap;             // The builder swap associated with this bean (if it has one).

-	private final MetadataMap extMeta;                      // Extended metadata

 	private final BeanContext beanContext;                  // The bean context that created this object.

 	private final ClassMeta<?>

 		elementType,                                         // If ARRAY or COLLECTION, the element class type.

@@ -143,7 +141,6 @@
 		this.innerClass = innerClass;

 		this.info = ClassInfo.of(innerClass);

 		this.beanContext = beanContext;

-		this.extMeta = new MetadataMap();

 		String notABeanReason = null;

 

 		wLock.lock();

@@ -253,7 +250,6 @@
 		this.pojoSwaps = mainType.pojoSwaps;

 		this.builderSwap = mainType.builderSwap;

 		this.beanFilter = mainType.beanFilter;

-		this.extMeta = mainType.extMeta;

 		this.initException = mainType.initException;

 		this.beanRegistry = mainType.beanRegistry;

 		this.exampleMethod = mainType.exampleMethod;

@@ -270,7 +266,6 @@
 	ClassMeta(ClassMeta<?>[] args) {

 		this.innerClass = (Class<T>) Object[].class;

 		this.info = ClassInfo.of(innerClass);

-		this.extMeta = new MetadataMap();

 		this.args = args;

 		this.implClass = null;

 		this.childPojoSwaps = null;

@@ -1524,16 +1519,6 @@
 	}

 

 	/**

-	 * Returns the language-specified extended metadata on this class.

-	 *

-	 * @param c The name of the metadata class to create.

-	 * @return Extended metadata on this class.  Never <jk>null</jk>.

-	 */

-	public <M extends ClassMetaExtended> M getExtendedMeta(Class<M> c) {

-		return extMeta.get(c, this);

-	}

-

-	/**

 	 * Returns the interface proxy invocation handler for this class.

 	 *

 	 * @return The interface proxy invocation handler, or <jk>null</jk> if it does not exist.

@@ -1778,20 +1763,6 @@
 	}

 

 	/**

-	 * Checks to see if the specified class type is the same as this one.

-	 *

-	 * @param t The specified class type.

-	 * @return <jk>true</jk> if the specified class type is the same as the class for this type.

-	 */

-	@Override /* Object */

-	public boolean equals(Object t) {

-		if (t == null || ! (t instanceof ClassMeta))

-			return false;

-		ClassMeta<?> t2 = (ClassMeta<?>)t;

-		return t2.getInnerClass() == this.getInnerClass();

-	}

-

-	/**

 	 * Similar to {@link #equals(Object)} except primitive and Object types that are similar are considered the same.

 	 * (e.g. <jk>boolean</jk> == <c>Boolean</c>).

 	 *

@@ -1885,11 +1856,6 @@
 		return innerClass.getSimpleName();

 	}

 

-	@Override /* Object */

-	public int hashCode() {

-		return super.hashCode();

-	}

-

 	/**

 	 * Returns <jk>true</jk> if this class has a transform associated with it that allows it to be created from a Reader.

 	 *

@@ -2079,4 +2045,17 @@
 	public <A extends Annotation> A getAnnotation(Class<A> a) {

 		return this.innerClass.getAnnotation(a);

 	}

+

+	@Override /* Object */

+	public int hashCode() {

+		return innerClass.hashCode();

+	}

+

+	@Override /* Object */

+	public boolean equals(Object o) {

+		if (o == null || ! (o instanceof ClassMeta))

+			return false;

+		ClassMeta<?> o2 = (ClassMeta<?>)o;

+		return o2.innerClass.equals(innerClass);

+	}

 }

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedBeanMeta.java
similarity index 87%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedBeanMeta.java
index f4c2eab..f24d23f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedBeanMeta.java
@@ -14,12 +14,8 @@
 
 /**
  * Defines extended language-specific metadata associated with a bean.
- *
- * <p>
- * Serializers and parsers can implement their own language-specific metadata on a bean and retrieve the metadata using
- * the {@link BeanMeta#getExtendedMeta(Class)} method.
  */
-public class BeanMetaExtended {
+public class ExtendedBeanMeta extends ExtendedMeta {
 
 	private final BeanMeta<?> bm;
 
@@ -29,7 +25,7 @@
 	 * @param bm The metadata of the bean we're extending.
 	 * @throws BeanRuntimeException If any error occurred trying to construct the metadata.
 	 */
-	public BeanMetaExtended(BeanMeta<?> bm) throws BeanRuntimeException {
+	public ExtendedBeanMeta(BeanMeta<?> bm) throws BeanRuntimeException {
 		this.bm = bm;
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMetaExtended.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedBeanPropertyMeta.java
similarity index 87%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMetaExtended.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedBeanPropertyMeta.java
index 43362f2..5109637 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanPropertyMetaExtended.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedBeanPropertyMeta.java
@@ -14,12 +14,8 @@
 
 /**
  * Defines extended language-specific metadata associated with a bean property.
- *
- * <p>
- * Serializers and parsers can implement their own language-specific metadata on a bean property and retrieve
- * the metadata using the {@link BeanPropertyMeta#getExtendedMeta(Class)} method.
  */
-public class BeanPropertyMetaExtended {
+public class ExtendedBeanPropertyMeta extends ExtendedMeta {
 
 	private final BeanPropertyMeta bpm;
 
@@ -29,7 +25,7 @@
 	 * @param bpm The metadata of the bean property we're extending.
 	 * @throws BeanRuntimeException If any error occurred trying to construct the metadata.
 	 */
-	public BeanPropertyMetaExtended(BeanPropertyMeta bpm) throws BeanRuntimeException {
+	public ExtendedBeanPropertyMeta(BeanPropertyMeta bpm) throws BeanRuntimeException {
 		this.bpm = bpm;
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMetaExtended.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedClassMeta.java
similarity index 88%
rename from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMetaExtended.java
rename to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedClassMeta.java
index b085de1..ae10c67 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ClassMetaExtended.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedClassMeta.java
@@ -14,12 +14,8 @@
 
 /**
  * Defines extended language-specific metadata associated with a class.
- *
- * <p>
- * Serializers and parsers can implement their own language-specific metadata on a class and retrieve the metadata
- * using the {@link ClassMeta#getExtendedMeta(Class)} method.
  */
-public class ClassMetaExtended {
+public class ExtendedClassMeta extends ExtendedMeta {
 
 	private final ClassMeta<?> cm;
 
@@ -29,7 +25,7 @@
 	 * @param cm The metadata of the class we're extending.
 	 * @throws BeanRuntimeException If any error occurred trying to construct the metadata.
 	 */
-	public ClassMetaExtended(ClassMeta<?> cm) throws BeanRuntimeException {
+	public ExtendedClassMeta(ClassMeta<?> cm) throws BeanRuntimeException {
 		this.cm = cm;
 	}
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedMeta.java
similarity index 66%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedMeta.java
index f4c2eab..2ac483c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/ExtendedMeta.java
@@ -13,32 +13,6 @@
 package org.apache.juneau;
 
 /**
- * Defines extended language-specific metadata associated with a bean.
- *
- * <p>
- * Serializers and parsers can implement their own language-specific metadata on a bean and retrieve the metadata using
- * the {@link BeanMeta#getExtendedMeta(Class)} method.
+ * Superclass of all extended metadata classes.
  */
-public class BeanMetaExtended {
-
-	private final BeanMeta<?> bm;
-
-	/**
-	 * Constructor.
-	 *
-	 * @param bm The metadata of the bean we're extending.
-	 * @throws BeanRuntimeException If any error occurred trying to construct the metadata.
-	 */
-	public BeanMetaExtended(BeanMeta<?> bm) throws BeanRuntimeException {
-		this.bm = bm;
-	}
-
-	/**
-	 * Returns the bean metadata that was passed into the constructor.
-	 *
-	 * @return The bean metadata that was passed into the constructor.
-	 */
-	protected BeanMeta<?> getBeanMeta() {
-		return bm;
-	}
-}
+public class ExtendedMeta {}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
index 3943455..5fea34b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlBeanPropertyMeta.java
@@ -22,7 +22,7 @@
  * annotation on the bean property.

  */

 @SuppressWarnings("rawtypes")

-public final class HtmlBeanPropertyMeta extends BeanPropertyMetaExtended {

+public final class HtmlBeanPropertyMeta extends ExtendedBeanPropertyMeta {

 

 	/**

 	 * Default instance.

@@ -38,9 +38,9 @@
 	 * Constructor.

 	 *

 	 * @param bpm The metadata of the bean property of this additional metadata.

-	 * @throws Exception If render class could not be instantiated.

+	 * @param htmlMetaProvider HTML metadata provider (for finding information about other artifacts).

 	 */

-	public HtmlBeanPropertyMeta(BeanPropertyMeta bpm) throws Exception {

+	public HtmlBeanPropertyMeta(BeanPropertyMeta bpm, HtmlMetaProvider htmlMetaProvider) {

 		super(bpm);

 		Builder b = new Builder();

 		if (bpm.getInnerField() != null)

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlClassMeta.java
index 1590c2e..86890b7 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlClassMeta.java
@@ -21,7 +21,7 @@
  * Metadata on classes specific to the HTML serializers and parsers pulled from the {@link Html @Html} annotation on

  * the class.

  */

-public class HtmlClassMeta extends ClassMetaExtended {

+public class HtmlClassMeta extends ExtendedClassMeta {

 

 	private final Html html;

 	private final boolean noTables, noTableHeaders;

@@ -32,8 +32,9 @@
 	 * Constructor.

 	 *

 	 * @param cm The class that this annotation is defined on.

+	 * @param htmlMetaProvider HTML metadata provider (for finding information about other artifacts).

 	 */

-	public HtmlClassMeta(ClassMeta<?> cm) {

+	public HtmlClassMeta(ClassMeta<?> cm, HtmlMetaProvider htmlMetaProvider) {

 		super(cm);

 		this.html = cm.getInfo().getAnnotation(Html.class);

 		if (html != null) {

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlMetaProvider.java
similarity index 66%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlMetaProvider.java
index f4c2eab..74c7949 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlMetaProvider.java
@@ -10,35 +10,28 @@
 // * "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.apache.juneau;
+package org.apache.juneau.html;
+
+import org.apache.juneau.*;
 
 /**
- * Defines extended language-specific metadata associated with a bean.
- *
- * <p>
- * Serializers and parsers can implement their own language-specific metadata on a bean and retrieve the metadata using
- * the {@link BeanMeta#getExtendedMeta(Class)} method.
+ * Interface for providing access to {@link HtmlClassMeta} and {@link HtmlBeanPropertyMeta} objects.
  */
-public class BeanMetaExtended {
-
-	private final BeanMeta<?> bm;
+public interface HtmlMetaProvider {
 
 	/**
-	 * Constructor.
+	 * Returns the language-specific metadata on the specified class.
 	 *
-	 * @param bm The metadata of the bean we're extending.
-	 * @throws BeanRuntimeException If any error occurred trying to construct the metadata.
+	 * @param cm The class to return the metadata on.
+	 * @return The metadata.
 	 */
-	public BeanMetaExtended(BeanMeta<?> bm) throws BeanRuntimeException {
-		this.bm = bm;
-	}
+	HtmlClassMeta getHtmlClassMeta(ClassMeta<?> cm);
 
 	/**
-	 * Returns the bean metadata that was passed into the constructor.
+	 * Returns the language-specific metadata on the specified bean property.
 	 *
-	 * @return The bean metadata that was passed into the constructor.
+	 * @param bpm The bean property to return the metadata on.
+	 * @return The metadata.
 	 */
-	protected BeanMeta<?> getBeanMeta() {
-		return bm;
-	}
+	HtmlBeanPropertyMeta getHtmlBeanPropertyMeta(BeanPropertyMeta bpm);
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParser.java
index d8220b3..e6bd2c4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParser.java
@@ -12,6 +12,9 @@
 // ***************************************************************************************************************************

 package org.apache.juneau.html;

 

+import java.util.*;

+import java.util.concurrent.*;

+

 import org.apache.juneau.*;

 import org.apache.juneau.annotation.*;

 import org.apache.juneau.parser.*;

@@ -31,7 +34,7 @@
  * This class is used primarily for automated testing of the {@link HtmlSerializer} class.

  */

 @ConfigurableContext

-public class HtmlParser extends XmlParser {

+public class HtmlParser extends XmlParser implements HtmlMetaProvider {

 

 	//-------------------------------------------------------------------------------------------------------------------

 	// Configurable properties

@@ -51,6 +54,9 @@
 	// Instance

 	//-------------------------------------------------------------------------------------------------------------------

 

+	private final Map<ClassMeta<?>,HtmlClassMeta> htmlClassMetas = new ConcurrentHashMap<>();

+	private final Map<BeanPropertyMeta,HtmlBeanPropertyMeta> htmlBeanPropertyMetas = new ConcurrentHashMap<>();

+

 	/**

 	 * Constructor.

 	 *

@@ -92,6 +98,32 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	@Override /* HtmlMetaProvider */

+	public HtmlClassMeta getHtmlClassMeta(ClassMeta<?> cm) {

+		HtmlClassMeta m = htmlClassMetas.get(cm);

+		if (m == null) {

+			m = new HtmlClassMeta(cm, this);

+			htmlClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	@Override /* HtmlMetaProvider */

+	public HtmlBeanPropertyMeta getHtmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		if (bpm == null)

+			return HtmlBeanPropertyMeta.DEFAULT;

+		HtmlBeanPropertyMeta m = htmlBeanPropertyMetas.get(bpm);

+		if (m == null) {

+			m = new HtmlBeanPropertyMeta(bpm.getDelegateFor(), this);

+			htmlBeanPropertyMetas.put(bpm, m);

+		}

+		return m;

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
index 8e66874..6ad4d2b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlParserSession.java
@@ -44,6 +44,8 @@
 		)

 	);

 

+	private final HtmlParser ctx;

+

 	/**

 	 * Create a new session using properties specified in the context.

 	 *

@@ -55,6 +57,7 @@
 	 */

 	protected HtmlParserSession(HtmlParser ctx, ParserSessionArgs args) {

 		super(ctx, args);

+		this.ctx = ctx;

 	}

 

 	@Override /* ParserSession */

@@ -120,7 +123,7 @@
 			throw new ParseException(this, "Unexpected end of stream in parseAnything for type ''{0}''", eType);

 

 		// Handle @Html(asXml=true) beans.

-		HtmlClassMeta hcm = sType.getExtendedMeta(HtmlClassMeta.class);

+		HtmlClassMeta hcm = getHtmlClassMeta(sType);

 		if (hcm.getFormat() == HtmlFormat.XML)

 			return super.parseAnything(eType, null, r, outer, false, pMeta);

 

@@ -154,8 +157,7 @@
 			else

 				isValid = false;

 

-		} else if (tag == STRING || (tag == A && pMeta != null

-				&& pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).getLink() != null)) {

+		} else if (tag == STRING || (tag == A && pMeta != null && getHtmlBeanPropertyMeta(pMeta).getLink() != null)) {

 			String text = getElementText(r);

 			if (sType.isObject() || sType.isCharSequence())

 				o = text;

@@ -738,6 +740,30 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	/**

+	 * Returns the language-specific metadata on the specified class.

+	 *

+	 * @param cm The class to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected HtmlClassMeta getHtmlClassMeta(ClassMeta<?> cm) {

+		return ctx.getHtmlClassMeta(cm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean property.

+	 *

+	 * @param bpm The bean property to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected HtmlBeanPropertyMeta getHtmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		return ctx.getHtmlBeanPropertyMeta(bpm);

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java
index b41435d..1ba0e2f 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializer.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.html;

 

 import java.util.*;

+import java.util.concurrent.*;

 

 import org.apache.juneau.*;

 import org.apache.juneau.annotation.*;

@@ -124,7 +125,7 @@
  * </p>

  */

 @ConfigurableContext

-public class HtmlSerializer extends XmlSerializer {

+public class HtmlSerializer extends XmlSerializer implements HtmlMetaProvider {

 

 	//-------------------------------------------------------------------------------------------------------------------

 	// Configurable properties

@@ -635,6 +636,8 @@
 		addKeyValueTableHeaders,

 		addBeanTypes;

 	private final String labelParameter;

+	private final Map<ClassMeta<?>,HtmlClassMeta> htmlClassMetas = new ConcurrentHashMap<>();

+	private final Map<BeanPropertyMeta,HtmlBeanPropertyMeta> htmlBeanPropertyMetas = new ConcurrentHashMap<>();

 

 	private volatile HtmlSchemaSerializer schemaSerializer;

 

@@ -724,6 +727,32 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	@Override /* HtmlMetaProvider */

+	public HtmlClassMeta getHtmlClassMeta(ClassMeta<?> cm) {

+		HtmlClassMeta m = htmlClassMetas.get(cm);

+		if (m == null) {

+			m = new HtmlClassMeta(cm, this);

+			htmlClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	@Override /* HtmlMetaProvider */

+	public HtmlBeanPropertyMeta getHtmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		if (bpm == null)

+			return HtmlBeanPropertyMeta.DEFAULT;

+		HtmlBeanPropertyMeta m = htmlBeanPropertyMetas.get(bpm);

+		if (m == null) {

+			m = new HtmlBeanPropertyMeta(bpm.getDelegateFor(), this);

+			htmlBeanPropertyMetas.put(bpm, m);

+		}

+		return m;

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Properties

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
index 7213563..fff755e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/html/HtmlSerializerSession.java
@@ -198,7 +198,7 @@
 				type = getClassMetaForObject(o);

 		}

 

-		HtmlClassMeta cHtml = cHtml(type);

+		HtmlClassMeta cHtml = getHtmlClassMeta(type);

 

 		if (type.isMapOrBean() && ! cHtml.isXml())

 			return serializeAnything(out, o, eType, elementName, pMeta, 0, false, false);

@@ -290,8 +290,8 @@
 				return ContentResult.CR_MIXED;

 			}

 

-			HtmlClassMeta cHtml = cHtml(sType);

-			HtmlBeanPropertyMeta bpHtml = bpHtml(pMeta);

+			HtmlClassMeta cHtml = getHtmlClassMeta(sType);

+			HtmlBeanPropertyMeta bpHtml = getHtmlBeanPropertyMeta(pMeta);

 

 			HtmlRender render = firstNonNull(bpHtml.getRender(), cHtml.getRender());

 

@@ -388,8 +388,8 @@
 		ClassMeta<?> keyType = eKeyType == null ? string() : eKeyType;

 		ClassMeta<?> valueType = eValueType == null ? object() : eValueType;

 		ClassMeta<?> aType = getClassMetaForObject(m);       // The actual type

-		HtmlClassMeta cHtml = cHtml(aType);

-		HtmlBeanPropertyMeta bpHtml = bpHtml(ppMeta);

+		HtmlClassMeta cHtml = getHtmlClassMeta(aType);

+		HtmlBeanPropertyMeta bpHtml = getHtmlBeanPropertyMeta(ppMeta);

 

 		int i = indent;

 

@@ -445,8 +445,8 @@
 

 	private void serializeBeanMap(XmlWriter out, BeanMap<?> m, ClassMeta<?> eType, BeanPropertyMeta ppMeta) throws IOException, SerializeException {

 

-		HtmlClassMeta cHtml = cHtml(m.getClassMeta());

-		HtmlBeanPropertyMeta bpHtml = bpHtml(ppMeta);

+		HtmlClassMeta cHtml = getHtmlClassMeta(m.getClassMeta());

+		HtmlBeanPropertyMeta bpHtml = getHtmlBeanPropertyMeta(ppMeta);

 

 		int i = indent;

 

@@ -519,8 +519,8 @@
 	@SuppressWarnings({ "rawtypes", "unchecked" })

 	private void serializeCollection(XmlWriter out, Object in, ClassMeta<?> sType, ClassMeta<?> eType, String name, BeanPropertyMeta ppMeta) throws IOException, SerializeException {

 

-		HtmlClassMeta cHtml = cHtml(sType);

-		HtmlBeanPropertyMeta bpHtml = bpHtml(ppMeta);

+		HtmlClassMeta cHtml = getHtmlClassMeta(sType);

+		HtmlBeanPropertyMeta bpHtml = getHtmlBeanPropertyMeta(ppMeta);

 

 		Collection c = (sType.isCollection() ? (Collection)in : toList(sType.getInnerClass(), in));

 

@@ -667,37 +667,29 @@
 		}

 	}

 

-	private static HtmlRender<?> getRender(HtmlSerializerSession session, BeanPropertyMeta pMeta, Object value) {

+	private HtmlRender<?> getRender(HtmlSerializerSession session, BeanPropertyMeta pMeta, Object value) {

 		if (pMeta == null)

 			return null;

-		HtmlRender<?> render = bpHtml(pMeta).getRender();

+		HtmlRender<?> render = getHtmlBeanPropertyMeta(pMeta).getRender();

 		if (render != null)

 			return render;

 		ClassMeta<?> cMeta = session.getClassMetaForObject(value);

-		render = cMeta == null ? null : cHtml(cMeta).getRender();

+		render = cMeta == null ? null : getHtmlClassMeta(cMeta).getRender();

 		return render;

 	}

 

 	@SuppressWarnings({"rawtypes","unchecked"})

-	private static String getStyle(HtmlSerializerSession session, BeanPropertyMeta pMeta, Object value) {

+	private String getStyle(HtmlSerializerSession session, BeanPropertyMeta pMeta, Object value) {

 		HtmlRender render = getRender(session, pMeta, value);

 		return render == null ? null : render.getStyle(session, value);

 	}

 

-	private static String getLink(BeanPropertyMeta pMeta) {

-		return pMeta == null ? null : pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).getLink();

+	private String getLink(BeanPropertyMeta pMeta) {

+		return pMeta == null ? null : getHtmlBeanPropertyMeta(pMeta).getLink();

 	}

 

-	private static String getAnchorText(BeanPropertyMeta pMeta) {

-		return pMeta == null ? null : pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class).getAnchorText();

-	}

-

-	private static HtmlClassMeta cHtml(ClassMeta<?> cm) {

-		return cm.getExtendedMeta(HtmlClassMeta.class);

-	}

-

-	private static HtmlBeanPropertyMeta bpHtml(BeanPropertyMeta pMeta) {

-		return pMeta == null ? HtmlBeanPropertyMeta.DEFAULT : pMeta.getExtendedMeta(HtmlBeanPropertyMeta.class);

+	private String getAnchorText(BeanPropertyMeta pMeta) {

+		return pMeta == null ? null : getHtmlBeanPropertyMeta(pMeta).getAnchorText();

 	}

 

 	/*

@@ -733,7 +725,7 @@
 		if (cm.getInnerClass().isAnnotationPresent(HtmlLink.class))

 			return null;

 

-		HtmlClassMeta cHtml = cHtml(cm);

+		HtmlClassMeta cHtml = getHtmlClassMeta(cm);

 

 		if (cHtml.isNoTables() || bpHtml.isNoTables())

 			return null;

@@ -897,6 +889,30 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	/**

+	 * Returns the language-specific metadata on the specified class.

+	 *

+	 * @param cm The class to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected HtmlClassMeta getHtmlClassMeta(ClassMeta<?> cm) {

+		return ctx.getHtmlClassMeta(cm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean property.

+	 *

+	 * @param bpm The bean property to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected HtmlBeanPropertyMeta getHtmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		return ctx.getHtmlBeanPropertyMeta(bpm);

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonClassMeta.java
index 34fa895..11d6aa2 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonClassMeta.java
@@ -21,7 +21,7 @@
  * Metadata on classes specific to the JSON serializers and parsers pulled from the {@link Json @Json} annotation on

  * the class.

  */

-public class JsonClassMeta extends ClassMetaExtended {

+public class JsonClassMeta extends ExtendedClassMeta {

 

 	private final Json json;

 	private final String wrapperAttr;

@@ -30,8 +30,9 @@
 	 * Constructor.

 	 *

 	 * @param cm The class that this annotation is defined on.

+	 * @param jsonMetaProvider JSON metadata provider (for finding information about other artifacts).

 	 */

-	public JsonClassMeta(ClassMeta<?> cm) {

+	public JsonClassMeta(ClassMeta<?> cm, JsonMetaProvider jsonMetaProvider) {

 		super(cm);

 		this.json = cm.getInfo().getAnnotation(Json.class);

 		if (json != null) {

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonMetaProvider.java
similarity index 65%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonMetaProvider.java
index f4c2eab..9d28c35 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonMetaProvider.java
@@ -10,35 +10,20 @@
 // * "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.apache.juneau;
+package org.apache.juneau.json;
+
+import org.apache.juneau.*;
 
 /**
- * Defines extended language-specific metadata associated with a bean.
- *
- * <p>
- * Serializers and parsers can implement their own language-specific metadata on a bean and retrieve the metadata using
- * the {@link BeanMeta#getExtendedMeta(Class)} method.
+ * Interface for providing access to {@link JsonClassMeta} objects.
  */
-public class BeanMetaExtended {
-
-	private final BeanMeta<?> bm;
+public interface JsonMetaProvider {
 
 	/**
-	 * Constructor.
+	 * Returns the language-specific metadata on the specified class.
 	 *
-	 * @param bm The metadata of the bean we're extending.
-	 * @throws BeanRuntimeException If any error occurred trying to construct the metadata.
+	 * @param cm The class to return the metadata on.
+	 * @return The metadata.
 	 */
-	public BeanMetaExtended(BeanMeta<?> bm) throws BeanRuntimeException {
-		this.bm = bm;
-	}
-
-	/**
-	 * Returns the bean metadata that was passed into the constructor.
-	 *
-	 * @return The bean metadata that was passed into the constructor.
-	 */
-	protected BeanMeta<?> getBeanMeta() {
-		return bm;
-	}
+	JsonClassMeta getJsonClassMeta(ClassMeta<?> cm);
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParser.java
index 2aa051d..4272382 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParser.java
@@ -12,6 +12,9 @@
 // ***************************************************************************************************************************

 package org.apache.juneau.json;

 

+import java.util.*;

+import java.util.concurrent.*;

+

 import org.apache.juneau.*;

 import org.apache.juneau.annotation.*;

 import org.apache.juneau.parser.*;

@@ -100,7 +103,7 @@
  * The end result should be the same.

  */

 @ConfigurableContext

-public class JsonParser extends ReaderParser {

+public class JsonParser extends ReaderParser implements JsonMetaProvider {

 

 	//-------------------------------------------------------------------------------------------------------------------

 	// Configurable properties

@@ -196,6 +199,7 @@
 	//-------------------------------------------------------------------------------------------------------------------

 

 	private final boolean validateEnd;

+	private final Map<ClassMeta<?>,JsonClassMeta> jsonClassMetas = new ConcurrentHashMap<>();

 

 	/**

 	 * Constructor.

@@ -249,6 +253,20 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	@Override /* JsonMetaProvider */

+	public JsonClassMeta getJsonClassMeta(ClassMeta<?> cm) {

+		JsonClassMeta m = jsonClassMetas.get(cm);

+		if (m == null) {

+			m = new JsonClassMeta(cm, this);

+			jsonClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Properties

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
index 27faae0..a3e38cf 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonParserSession.java
@@ -125,11 +125,11 @@
 		else

 			sType = eType;

 

-		if (sType.isOptional()) 

+		if (sType.isOptional())

 			return (T)Optional.ofNullable(parseAnything(eType.getElementType(), r, outer, pMeta));

 

 		setCurrentClass(sType);

-		String wrapperAttr = sType.getExtendedMeta(JsonClassMeta.class).getWrapperAttr();

+		String wrapperAttr = getJsonClassMeta(sType).getWrapperAttr();

 

 		Object o = null;

 

@@ -801,6 +801,20 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	/**

+	 * Returns the language-specific metadata on the specified class.

+	 *

+	 * @param cm The class to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected JsonClassMeta getJsonClassMeta(ClassMeta<?> cm) {

+		return ctx.getJsonClassMeta(cm);

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java
index 5203ae9..1ec212a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSchemaSerializer.java
@@ -12,6 +12,9 @@
 // ***************************************************************************************************************************

 package org.apache.juneau.json;

 

+import java.util.*;

+import java.util.concurrent.*;

+

 import org.apache.juneau.*;

 import org.apache.juneau.annotation.*;

 import org.apache.juneau.jsonschema.*;

@@ -31,7 +34,7 @@
  * Produces the JSON-schema for the JSON produced by the {@link JsonSerializer} class with the same properties.

  */

 @ConfigurableContext

-public class JsonSchemaSerializer extends JsonSerializer {

+public class JsonSchemaSerializer extends JsonSerializer implements JsonSchemaMetaProvider {

 

 	//-------------------------------------------------------------------------------------------------------------------

 	// Configurable properties

@@ -118,6 +121,8 @@
 	//-------------------------------------------------------------------------------------------------------------------

 

 	private final JsonSchemaGenerator generator;

+	private final Map<ClassMeta<?>,JsonSchemaClassMeta> jsonSchemaClassMetas = new ConcurrentHashMap<>();

+	private final Map<BeanPropertyMeta,JsonSchemaBeanPropertyMeta> jsonSchemaBeanPropertyMetas = new ConcurrentHashMap<>();

 

 	/**

 	 * Constructor.

@@ -168,6 +173,30 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	@Override /* JsonSchemaMetaProvider */

+	public JsonSchemaClassMeta getJsonSchemaClassMeta(ClassMeta<?> cm) {

+		JsonSchemaClassMeta m = jsonSchemaClassMetas.get(cm);

+		if (m == null) {

+			m = new JsonSchemaClassMeta(cm, this);

+			jsonSchemaClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	@Override /* JsonSchemaMetaProvider */

+	public JsonSchemaBeanPropertyMeta getJsonSchemaBeanPropertyMeta(BeanPropertyMeta bpm) {

+		JsonSchemaBeanPropertyMeta m = jsonSchemaBeanPropertyMetas.get(bpm);

+		if (m == null) {

+			m = new JsonSchemaBeanPropertyMeta(bpm.getDelegateFor(), this);

+			jsonSchemaBeanPropertyMetas.put(bpm, m);

+		}

+		return m;

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSchemaSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSchemaSerializerSession.java
index ff17767..1e24f6e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSchemaSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSchemaSerializerSession.java
@@ -28,6 +28,7 @@
 public class JsonSchemaSerializerSession extends JsonSerializerSession {
 
 	private final JsonSchemaGeneratorSession genSession;
+	private final JsonSchemaSerializer ctx;
 
 	/**
 	 * Create a new session using properties specified in the context.
@@ -44,6 +45,7 @@
 	protected JsonSchemaSerializerSession(JsonSchemaSerializer ctx, SerializerSessionArgs args) {
 		super(ctx, args);
 		genSession = ctx.getGenerator().createSession(args);
+		this.ctx = ctx;
 	}
 
 	@Override /* SerializerSession */
@@ -56,6 +58,30 @@
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
+	// Extended metadata
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Returns the language-specific metadata on the specified class.
+	 *
+	 * @param cm The class to return the metadata on.
+	 * @return The metadata.
+	 */
+	protected JsonSchemaClassMeta getJsonSchemaClassMeta(ClassMeta<?> cm) {
+		return ctx.getJsonSchemaClassMeta(cm);
+	}
+
+	/**
+	 * Returns the language-specific metadata on the specified bean property.
+	 *
+	 * @param bpm The bean property to return the metadata on.
+	 * @return The metadata.
+	 */
+	protected JsonSchemaBeanPropertyMeta getJsonSchemaBeanPropertyMeta(BeanPropertyMeta bpm) {
+		return ctx.getJsonSchemaBeanPropertyMeta(bpm);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
 	// Other methods
 	//-----------------------------------------------------------------------------------------------------------------
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java
index ebcebb8..da53881 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializer.java
@@ -13,6 +13,7 @@
 package org.apache.juneau.json;

 

 import java.util.*;

+import java.util.concurrent.*;

 

 import org.apache.juneau.*;

 import org.apache.juneau.annotation.*;

@@ -88,7 +89,7 @@
  * </p>

  */

 @ConfigurableContext

-public class JsonSerializer extends WriterSerializer {

+public class JsonSerializer extends WriterSerializer implements JsonMetaProvider {

 

 	//-------------------------------------------------------------------------------------------------------------------

 	// Configurable properties

@@ -312,6 +313,7 @@
 		simpleMode,

 		escapeSolidus,

 		addBeanTypes;

+	private final Map<ClassMeta<?>,JsonClassMeta> jsonClassMetas = new ConcurrentHashMap<>();

 

 	private volatile JsonSchemaSerializer schemaSerializer;

 

@@ -406,6 +408,20 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	@Override /* JsonMetaProvider */

+	public JsonClassMeta getJsonClassMeta(ClassMeta<?> cm) {

+		JsonClassMeta m = jsonClassMetas.get(cm);

+		if (m == null) {

+			m = new JsonClassMeta(cm, this);

+			jsonClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Properties

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
index 3ed2bc2..f8ce995 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/json/JsonSerializerSession.java
@@ -127,7 +127,7 @@
 				sType = getClassMetaForObject(o);

 		}

 

-		String wrapperAttr = sType.getExtendedMeta(JsonClassMeta.class).getWrapperAttr();

+		String wrapperAttr = getJsonClassMeta(sType).getWrapperAttr();

 		if (wrapperAttr != null) {

 			out.append('{').cr(indent).attr(wrapperAttr).append(':').s(indent);

 			indent++;

@@ -308,6 +308,20 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	/**

+	 * Returns the language-specific metadata on the specified class.

+	 *

+	 * @param cm The class to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected JsonClassMeta getJsonClassMeta(ClassMeta<?> cm) {

+		return ctx.getJsonClassMeta(cm);

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
index 6d6f724..b3ebb91 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaBeanPropertyMeta.java
@@ -22,7 +22,7 @@
  * Metadata on bean properties specific to the JSON-Schema pulled from the {@link Schema @Schema} annotation

  * on the bean property.

  */

-public class JsonSchemaBeanPropertyMeta extends BeanPropertyMetaExtended {

+public class JsonSchemaBeanPropertyMeta extends ExtendedBeanPropertyMeta {

 

 	/**

 	 * Default instance.

@@ -35,8 +35,9 @@
 	 * Constructor.

 	 *

 	 * @param bpm The metadata of the bean property of this additional metadata.

+	 * @param jsonSchemaMetaProvider JSON-schema metadata provider (for finding information about other artifacts).

 	 */

-	public JsonSchemaBeanPropertyMeta(BeanPropertyMeta bpm) {

+	public JsonSchemaBeanPropertyMeta(BeanPropertyMeta bpm, JsonSchemaMetaProvider jsonSchemaMetaProvider) {

 		super(bpm);

 

 		this.schema = new ObjectMap();

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaClassMeta.java
index 2bc6446..2f7b9c8 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaClassMeta.java
@@ -14,12 +14,13 @@
 

 import org.apache.juneau.*;

 import org.apache.juneau.jsonschema.annotation.*;

+import org.apache.juneau.parser.*;

 

 /**

  * Metadata on classes specific to the JSON-Schema serializer and pulled from the {@link Schema @Schema} annotation on

  * the class.

  */

-public class JsonSchemaClassMeta extends ClassMetaExtended {

+public class JsonSchemaClassMeta extends ExtendedClassMeta {

 

 	private final ObjectMap schema;

 

@@ -27,12 +28,16 @@
 	 * Constructor.

 	 *

 	 * @param cm The class that this annotation is defined on.

-	 * @throws Exception If invalid <ja>@Schema</ja> definition was encountered.

+	 * @param jsonSchemaMetaProvider JSON-schema metadata provider (for finding information about other artifacts).

 	 */

-	public JsonSchemaClassMeta(ClassMeta<?> cm) throws Exception {

+	public JsonSchemaClassMeta(ClassMeta<?> cm, JsonSchemaMetaProvider jsonSchemaMetaProvider) {

 		super(cm);

-		Schema s = cm.getInfo().getAnnotation(Schema.class);

-		schema = s == null ? ObjectMap.EMPTY_MAP : SchemaUtils.asMap(s);

+		try {

+			Schema s = cm.getInfo().getAnnotation(Schema.class);

+			schema = s == null ? ObjectMap.EMPTY_MAP : SchemaUtils.asMap(s);

+		} catch (ParseException e) {

+			throw new RuntimeException(e);

+		}

 	}

 

 	/**

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java
index 3e34f7a..a1d8b2b 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGenerator.java
@@ -15,6 +15,7 @@
 import static org.apache.juneau.internal.StringUtils.*;
 
 import java.util.*;
+import java.util.concurrent.*;
 import java.util.regex.*;
 
 import org.apache.juneau.*;
@@ -25,7 +26,7 @@
  * Generates JSON-schema metadata about POJOs.
  */
 @ConfigurableContext
-public class JsonSchemaGenerator extends BeanTraverseContext {
+public class JsonSchemaGenerator extends BeanTraverseContext implements JsonSchemaMetaProvider {
 
 	//-------------------------------------------------------------------------------------------------------------------
 	// Configurable properties
@@ -282,6 +283,8 @@
 	private final Map<String,ObjectMap> defaultSchemas;
 	private final JsonSerializer jsonSerializer;
 	private final Set<Pattern> ignoreTypes;
+	private final Map<ClassMeta<?>,JsonSchemaClassMeta> jsonSchemaClassMetas = new ConcurrentHashMap<>();
+	private final Map<BeanPropertyMeta,JsonSchemaBeanPropertyMeta> jsonSchemaBeanPropertyMetas = new ConcurrentHashMap<>();
 
 	/**
 	 * Constructor.
@@ -431,6 +434,30 @@
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
+	// Extended metadata
+	//-----------------------------------------------------------------------------------------------------------------
+
+	@Override
+	public JsonSchemaClassMeta getJsonSchemaClassMeta(ClassMeta<?> cm) {
+		JsonSchemaClassMeta m = jsonSchemaClassMetas.get(cm);
+		if (m == null) {
+			m = new JsonSchemaClassMeta(cm, this);
+			jsonSchemaClassMetas.put(cm, m);
+		}
+		return m;
+	}
+
+	@Override
+	public JsonSchemaBeanPropertyMeta getJsonSchemaBeanPropertyMeta(BeanPropertyMeta bpm) {
+		JsonSchemaBeanPropertyMeta m = jsonSchemaBeanPropertyMetas.get(bpm);
+		if (m == null) {
+			m = new JsonSchemaBeanPropertyMeta(bpm, this);
+			jsonSchemaBeanPropertyMetas.put(bpm, m);
+		}
+		return m;
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
 	// Other methods
 	//-----------------------------------------------------------------------------------------------------------------
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorSession.java
index b4ea353..87780e7 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaGeneratorSession.java
@@ -140,9 +140,9 @@
 
 		JsonSchemaClassMeta jscm = null;
 		if (pojoSwap != null && pojoSwap.getClass().getAnnotation(Schema.class) != null)
-			jscm = getClassMeta(pojoSwap.getClass()).getExtendedMeta(JsonSchemaClassMeta.class);
+			jscm = getJsonSchemaClassMeta(getClassMeta(pojoSwap.getClass()));
 		if (jscm == null)
-			jscm = sType.getExtendedMeta(JsonSchemaClassMeta.class);
+			jscm = getJsonSchemaClassMeta(sType);
 
 		TypeCategory tc = null;
 
@@ -220,7 +220,7 @@
 				for (Iterator<BeanPropertyMeta> i = bm.getPropertyMetas().iterator(); i.hasNext();) {
 					BeanPropertyMeta p = i.next();
 					if (p.canRead())
-						properties.put(p.getName(), getSchema(p.getClassMeta(), p.getName(), p.getProperties(), exampleAdded, descriptionAdded, p.getExtendedMeta(JsonSchemaBeanPropertyMeta.class)));
+						properties.put(p.getName(), getSchema(p.getClassMeta(), p.getName(), p.getProperties(), exampleAdded, descriptionAdded, getJsonSchemaBeanPropertyMeta(p)));
 				}
 				out.put("properties", properties);
 
@@ -449,6 +449,30 @@
 	}
 
 	//-----------------------------------------------------------------------------------------------------------------
+	// Extended metadata
+	//-----------------------------------------------------------------------------------------------------------------
+
+	/**
+	 * Returns the language-specific metadata on the specified class.
+	 *
+	 * @param cm The class to return the metadata on.
+	 * @return The metadata.
+	 */
+	public JsonSchemaClassMeta getJsonSchemaClassMeta(ClassMeta<?> cm) {
+		return ctx.getJsonSchemaClassMeta(cm);
+	}
+
+	/**
+	 * Returns the language-specific metadata on the specified bean property.
+	 *
+	 * @param bpm The bean property to return the metadata on.
+	 * @return The metadata.
+	 */
+	public JsonSchemaBeanPropertyMeta getJsonSchemaBeanPropertyMeta(BeanPropertyMeta bpm) {
+		return ctx.getJsonSchemaBeanPropertyMeta(bpm);
+	}
+
+	//-----------------------------------------------------------------------------------------------------------------
 	// Utility methods
 	//-----------------------------------------------------------------------------------------------------------------
 
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaMetaProvider.java
similarity index 66%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaMetaProvider.java
index f4c2eab..9f34b9e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/jsonschema/JsonSchemaMetaProvider.java
@@ -10,35 +10,28 @@
 // * "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.apache.juneau;
+package org.apache.juneau.jsonschema;
+
+import org.apache.juneau.*;
 
 /**
- * Defines extended language-specific metadata associated with a bean.
- *
- * <p>
- * Serializers and parsers can implement their own language-specific metadata on a bean and retrieve the metadata using
- * the {@link BeanMeta#getExtendedMeta(Class)} method.
+ * Interface for providing access to {@link JsonSchemaClassMeta} and {@link JsonSchemaBeanPropertyMeta} objects.
  */
-public class BeanMetaExtended {
-
-	private final BeanMeta<?> bm;
+public interface JsonSchemaMetaProvider {
 
 	/**
-	 * Constructor.
+	 * Returns the language-specific metadata on the specified class.
 	 *
-	 * @param bm The metadata of the bean we're extending.
-	 * @throws BeanRuntimeException If any error occurred trying to construct the metadata.
+	 * @param cm The class to return the metadata on.
+	 * @return The metadata.
 	 */
-	public BeanMetaExtended(BeanMeta<?> bm) throws BeanRuntimeException {
-		this.bm = bm;
-	}
+	JsonSchemaClassMeta getJsonSchemaClassMeta(ClassMeta<?> cm);
 
 	/**
-	 * Returns the bean metadata that was passed into the constructor.
+	 * Returns the language-specific metadata on the specified bean property.
 	 *
-	 * @return The bean metadata that was passed into the constructor.
+	 * @param bpm The bean property to return the metadata on.
+	 * @return The metadata.
 	 */
-	protected BeanMeta<?> getBeanMeta() {
-		return bm;
-	}
+	JsonSchemaBeanPropertyMeta getJsonSchemaBeanPropertyMeta(BeanPropertyMeta bpm);
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingClassMeta.java
index 6f3e1bb..0b4de2d 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingClassMeta.java
@@ -18,7 +18,7 @@
 /**

  * Metadata on classes specific to the URL-Encoding serializers and parsers pulled from the {@link UrlEncoding @UrlEncoding} annotation on the class.

  */

-public class UrlEncodingClassMeta extends ClassMetaExtended {

+public class UrlEncodingClassMeta extends ExtendedClassMeta {

 

 	private final UrlEncoding urlEncoding;

 	private final boolean expandedParams;

@@ -27,8 +27,9 @@
 	 * Constructor.

 	 *

 	 * @param cm The class that this annotation is defined on.

+	 * @param urlEncodingMetaProvider URL-encoding metadata provider (for finding information about other artifacts).

 	 */

-	public UrlEncodingClassMeta(ClassMeta<?> cm) {

+	public UrlEncodingClassMeta(ClassMeta<?> cm, UrlEncodingMetaProvider urlEncodingMetaProvider) {

 		super(cm);

 		this.urlEncoding = cm.getInfo().getAnnotation(UrlEncoding.class);

 		if (urlEncoding != null) {

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingMetaProvider.java
similarity index 65%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingMetaProvider.java
index f4c2eab..e7d5e2c 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingMetaProvider.java
@@ -10,35 +10,20 @@
 // * "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.apache.juneau;
+package org.apache.juneau.urlencoding;
+
+import org.apache.juneau.*;
 
 /**
- * Defines extended language-specific metadata associated with a bean.
- *
- * <p>
- * Serializers and parsers can implement their own language-specific metadata on a bean and retrieve the metadata using
- * the {@link BeanMeta#getExtendedMeta(Class)} method.
+ * Interface for providing access to {@link UrlEncodingClassMeta} objects.
  */
-public class BeanMetaExtended {
-
-	private final BeanMeta<?> bm;
+public interface UrlEncodingMetaProvider {
 
 	/**
-	 * Constructor.
+	 * Returns the language-specific metadata on the specified class.
 	 *
-	 * @param bm The metadata of the bean we're extending.
-	 * @throws BeanRuntimeException If any error occurred trying to construct the metadata.
+	 * @param cm The class to return the metadata on.
+	 * @return The metadata.
 	 */
-	public BeanMetaExtended(BeanMeta<?> bm) throws BeanRuntimeException {
-		this.bm = bm;
-	}
-
-	/**
-	 * Returns the bean metadata that was passed into the constructor.
-	 *
-	 * @return The bean metadata that was passed into the constructor.
-	 */
-	protected BeanMeta<?> getBeanMeta() {
-		return bm;
-	}
+	UrlEncodingClassMeta getUrlEncodingClassMeta(ClassMeta<?> cm);
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java
index df5e6c3..0efa945 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParser.java
@@ -12,6 +12,9 @@
 // ***************************************************************************************************************************

 package org.apache.juneau.urlencoding;

 

+import java.util.*;

+import java.util.concurrent.*;

+

 import org.apache.juneau.*;

 import org.apache.juneau.annotation.*;

 import org.apache.juneau.parser.*;

@@ -36,7 +39,7 @@
  * This parser uses a state machine, which makes it very fast and efficient.

  */

 @ConfigurableContext

-public class UrlEncodingParser extends UonParser {

+public class UrlEncodingParser extends UonParser implements UrlEncodingMetaProvider {

 

 	//-------------------------------------------------------------------------------------------------------------------

 	// Configurable properties

@@ -110,6 +113,7 @@
 	//-------------------------------------------------------------------------------------------------------------------

 

 	private final boolean expandedParams;

+	private final Map<ClassMeta<?>,UrlEncodingClassMeta> urlEncodingClassMetas = new ConcurrentHashMap<>();

 

 	/**

 	 * Constructor.

@@ -163,6 +167,20 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	@Override /* UrlEncodingMetaProvider */

+	public UrlEncodingClassMeta getUrlEncodingClassMeta(ClassMeta<?> cm) {

+		UrlEncodingClassMeta m = urlEncodingClassMetas.get(cm);

+		if (m == null) {

+			m = new UrlEncodingClassMeta(cm, this);

+			urlEncodingClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Properties

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java
index 5bbc18d..5e63330 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingParserSession.java
@@ -59,7 +59,7 @@
 		if (cm.isCollectionOrArray()) {

 			if (isExpandedParams())

 				return true;

-			if (pMeta.getBeanMeta().getClassMeta().getExtendedMeta(UrlEncodingClassMeta.class).isExpandedParams())

+			if (getUrlEncodingClassMeta(pMeta.getBeanMeta().getClassMeta()).isExpandedParams())

 				return true;

 		}

 		return false;

@@ -95,8 +95,8 @@
 			sType = swap.getSwapClassMeta(this);

 		else

 			sType = eType;

-		

-		if (sType.isOptional()) 

+

+		if (sType.isOptional())

 			return (T)Optional.ofNullable(parseAnything(eType.getElementType(), r, outer));

 

 		int c = r.peekSkipWs();

@@ -372,6 +372,20 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	/**

+	 * Returns the language-specific metadata on the specified class.

+	 *

+	 * @param cm The class to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected UrlEncodingClassMeta getUrlEncodingClassMeta(ClassMeta<?> cm) {

+		return ctx.getUrlEncodingClassMeta(cm);

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
index 1741ccb..61bfd92 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializer.java
@@ -12,6 +12,9 @@
 // ***************************************************************************************************************************

 package org.apache.juneau.urlencoding;

 

+import java.util.*;

+import java.util.concurrent.*;

+

 import org.apache.juneau.*;

 import org.apache.juneau.annotation.*;

 import org.apache.juneau.serializer.*;

@@ -112,7 +115,7 @@
  * </p>

  */

 @ConfigurableContext

-public class UrlEncodingSerializer extends UonSerializer {

+public class UrlEncodingSerializer extends UonSerializer implements UrlEncodingMetaProvider {

 

 	//-------------------------------------------------------------------------------------------------------------------

 	// Configurable properties

@@ -249,6 +252,7 @@
 

 	private final boolean

 		expandedParams;

+	private final Map<ClassMeta<?>,UrlEncodingClassMeta> urlEncodingClassMetas = new ConcurrentHashMap<>();

 

 	/**

 	 * Constructor.

@@ -334,6 +338,20 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	@Override /* UrlEncodingMetaProvider */

+	public UrlEncodingClassMeta getUrlEncodingClassMeta(ClassMeta<?> cm) {

+		UrlEncodingClassMeta m = urlEncodingClassMetas.get(cm);

+		if (m == null) {

+			m = new UrlEncodingClassMeta(cm, this);

+			urlEncodingClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Properties

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
index 10dd525..0d7d786 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/urlencoding/UrlEncodingSerializerSession.java
@@ -62,7 +62,7 @@
 		if (cm.isCollectionOrArray()) {

 			if (isExpandedParams())

 				return true;

-			if (pMeta.getBeanMeta().getClassMeta().getExtendedMeta(UrlEncodingClassMeta.class).isExpandedParams())

+			if (getUrlEncodingClassMeta(pMeta.getBeanMeta().getClassMeta()).isExpandedParams())

 				return true;

 		}

 		return false;

@@ -276,6 +276,20 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	/**

+	 * Returns the language-specific metadata on the specified class.

+	 *

+	 * @param cm The class to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected UrlEncodingClassMeta getUrlEncodingClassMeta(ClassMeta<?> cm) {

+		return ctx.getUrlEncodingClassMeta(cm);

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MetadataMap.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MetadataMap.java
deleted file mode 100644
index 207a36e..0000000
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/utils/MetadataMap.java
+++ /dev/null
@@ -1,84 +0,0 @@
-// ***************************************************************************************************************************
-// * Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements.  See the NOTICE file *
-// * distributed with this work for additional information regarding copyright ownership.  The ASF licenses this file        *
-// * to you 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.apache.juneau.utils;
-
-import java.lang.reflect.*;
-
-import org.apache.juneau.*;
-import org.apache.juneau.reflect.*;
-
-/**
- * Utility class for quick lookup of class metadata instances.
- *
- * <p>
- * Class instances are created once and then cached.
- *
- * <p>
- * Classes must have a constructor that takes in a single argument.
- */
-public class MetadataMap {
-
-	private Class<?>[] classes = new Class<?>[0];
-	private Object[] metadata = new Object[0];
-
-
-	/**
-	 * Constructor.
-	 *
-	 * @param c The metadata class to create.
-	 * @param constructorArg The argument needed to construct the metadata.
-	 * @return The cached metadata object.
-	 */
-	@SuppressWarnings("unchecked")
-	public <T> T get(Class<T> c, Object constructorArg) {
-		for (int i = 0; i < classes.length; i++)
-			if (classes[i] == c)
-				return (T)metadata[i];
-		synchronized(this) {
-			for (int i = 0; i < classes.length; i++)
-				if (classes[i] == c)
-					return (T)metadata[i];
-			Class<?>[] classes2 = new Class<?>[classes.length + 1];
-			Object[] metadata2 = new Object[classes.length + 1];
-			for (int i = 0; i < classes.length; i++) {
-				classes2[i] = classes[i];
-				metadata2[i] = metadata[i];
-			}
-			Object o = null;
-			try {
-				for (Constructor<?> con : c.getConstructors()) {
-					Class<?>[] pt = con.getParameterTypes();
-					if (pt.length == 1 && ClassInfo.of(pt[0]).isParentOf(constructorArg.getClass())) {
-						o = con.newInstance(constructorArg);
-						break;
-					}
-				}
-			} catch (InvocationTargetException e) {
-				Throwable t = e.getTargetException();
-				if (t instanceof RuntimeException)
-					throw (RuntimeException)t;
-				throw new RuntimeException(t);
-			} catch (Exception e) {
-				throw new RuntimeException(e);
-			}
-			if (o == null)
-				throw new BeanRuntimeException(c,
-					"Could not find a constructor on class with a parameter to handle type {0}", constructorArg.getClass());
-			classes2[classes.length] = c;
-			metadata2[classes.length] = o;
-			classes = classes2;
-			metadata = metadata2;
-			return (T)o;
-		}
-	}
-}
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanMeta.java
index 9fbb27d..9924b2e 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanMeta.java
@@ -24,7 +24,7 @@
  * Metadata on beans specific to the XML serializers and parsers pulled from the {@link Xml @Xml} annotation on the

  * class.

  */

-public class XmlBeanMeta extends BeanMetaExtended {

+public class XmlBeanMeta extends ExtendedBeanMeta {

 

 	// XML related fields

 	private final Map<String,BeanPropertyMeta> attrs;                        // Map of bean properties that are represented as XML attributes.

@@ -38,12 +38,13 @@
 	 * Constructor.

 	 *

 	 * @param beanMeta The metadata on the bean that this metadata applies to.

+	 * @param xmlMetaProvider XML metadata provider (for finding information about other artifacts).

 	 */

-	public XmlBeanMeta(BeanMeta<?> beanMeta) {

+	public XmlBeanMeta(BeanMeta<?> beanMeta, XmlMetaProvider xmlMetaProvider) {

 		super(beanMeta);

 

 		Class<?> c = beanMeta.getClassMeta().getInnerClass();

-		XmlBeanMetaBuilder b = new XmlBeanMetaBuilder(beanMeta);

+		XmlBeanMetaBuilder b = new XmlBeanMetaBuilder(beanMeta, xmlMetaProvider);

 

 		attrs = unmodifiableMap(b.attrs);

 		elements = unmodifiableMap(b.elements);

@@ -76,7 +77,7 @@
 			contentProperty;

 		XmlFormat contentFormat = DEFAULT;

 

-		XmlBeanMetaBuilder(BeanMeta<?> beanMeta) {

+		XmlBeanMetaBuilder(BeanMeta<?> beanMeta, XmlMetaProvider xmlMetaProvider) {

 			Class<?> c = beanMeta.getClassMeta().getInnerClass();

 			Xml xml = c.getAnnotation(Xml.class);

 			XmlFormat defaultFormat = null;

@@ -96,7 +97,7 @@
 			}

 

 			for (BeanPropertyMeta p : beanMeta.getPropertyMetas()) {

-				XmlFormat xf = p.getExtendedMeta(XmlBeanPropertyMeta.class).getXmlFormat();

+				XmlFormat xf = xmlMetaProvider.getXmlBeanPropertyMeta(p).getXmlFormat();

 				ClassMeta<?> pcm = p.getClassMeta();

 				if (xf == ATTR) {

 					attrs.put(p.getName(), p);

@@ -127,7 +128,7 @@
 					contentFormat = xf;

 				}

 				// Look for any properties that are collections with @Xml.childName specified.

-				String n = p.getExtendedMeta(XmlBeanPropertyMeta.class).getChildName();

+				String n = xmlMetaProvider.getXmlBeanPropertyMeta(p).getChildName();

 				if (n != null) {

 					if (collapsedProperties.containsKey(n) && collapsedProperties.get(n) != p)

 						throw new BeanRuntimeException(c, "Multiple properties found with the child name ''{0}''.", n);

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
index a98013f..1a979c4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlBeanPropertyMeta.java
@@ -21,7 +21,7 @@
  * Metadata on bean properties specific to the XML serializers and parsers pulled from the {@link Xml @Xml} annotation

  * on the bean property.

  */

-public class XmlBeanPropertyMeta extends BeanPropertyMetaExtended {

+public class XmlBeanPropertyMeta extends ExtendedBeanPropertyMeta {

 

 	/**

 	 * Default instance.

@@ -31,14 +31,17 @@
 	private Namespace namespace = null;

 	private XmlFormat xmlFormat = XmlFormat.DEFAULT;

 	private String childName;

+	private final XmlMetaProvider xmlMetaProvider;

 

 	/**

 	 * Constructor.

 	 *

 	 * @param bpm The metadata of the bean property of this additional metadata.

+	 * @param xmlMetaProvider XML metadata provider (for finding information about other artifacts).

 	 */

-	public XmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+	public XmlBeanPropertyMeta(BeanPropertyMeta bpm, XmlMetaProvider xmlMetaProvider) {

 		super(bpm);

+		this.xmlMetaProvider = xmlMetaProvider;

 

 		if (bpm.getInnerField() != null)

 			findXmlInfo(bpm.getInnerField().getAnnotation(Xml.class));

@@ -48,11 +51,12 @@
 			findXmlInfo(bpm.getSetter().getAnnotation(Xml.class));

 

 		if (namespace == null)

-			namespace = bpm.getBeanMeta().getClassMeta().getExtendedMeta(XmlClassMeta.class).getNamespace();

+			namespace = xmlMetaProvider.getXmlClassMeta(bpm.getBeanMeta().getClassMeta()).getNamespace();

 	}

 

 	private XmlBeanPropertyMeta() {

 		super(null);

+		this.xmlMetaProvider = null;

 	}

 

 	/**

@@ -120,8 +124,8 @@
 

 		if (xmlFormat == XmlFormat.COLLAPSED) {

 			if (isCollection) {

-				if (cen.isEmpty())

-					cen = cmProperty.getExtendedMeta(XmlClassMeta.class).getChildName();

+				if (cen.isEmpty() && xmlMetaProvider != null)

+					cen = xmlMetaProvider.getXmlClassMeta(cmProperty).getChildName();

 				if (cen == null || cen.isEmpty())

 					cen = cmProperty.getElementType().getDictionaryName();

 				if (cen == null || cen.isEmpty())

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlClassMeta.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlClassMeta.java
index c6d902f..3d111ee 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlClassMeta.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlClassMeta.java
@@ -24,7 +24,7 @@
  * Metadata on classes specific to the XML serializers and parsers pulled from the {@link Xml @Xml} annotation on the

  * class.

  */

-public class XmlClassMeta extends ClassMetaExtended {

+public class XmlClassMeta extends ExtendedClassMeta {

 

 	private final Namespace namespace;

 	private final Xml xml;

@@ -35,8 +35,9 @@
 	 * Constructor.

 	 *

 	 * @param cm The class that this annotation is defined on.

+	 * @param xmlMetaProvider XML metadata provider (for finding information about other artifacts).

 	 */

-	public XmlClassMeta(ClassMeta<?> cm) {

+	public XmlClassMeta(ClassMeta<?> cm, XmlMetaProvider xmlMetaProvider) {

 		super(cm);

 		this.namespace = findNamespace(cm);

 		this.xml = cm.getInfo().getAnnotation(Xml.class);

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlMetaProvider.java
similarity index 64%
copy from juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
copy to juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlMetaProvider.java
index f4c2eab..668763a 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/BeanMetaExtended.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlMetaProvider.java
@@ -10,35 +10,36 @@
 // * "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.apache.juneau;
+package org.apache.juneau.xml;
+
+import org.apache.juneau.*;
 
 /**
- * Defines extended language-specific metadata associated with a bean.
- *
- * <p>
- * Serializers and parsers can implement their own language-specific metadata on a bean and retrieve the metadata using
- * the {@link BeanMeta#getExtendedMeta(Class)} method.
+ * Interface for providing access to {@link XmlClassMeta}, {@link XmlBeanMeta}, and {@link XmlBeanPropertyMeta} objects.
  */
-public class BeanMetaExtended {
-
-	private final BeanMeta<?> bm;
+public interface XmlMetaProvider {
 
 	/**
-	 * Constructor.
+	 * Returns the language-specific metadata on the specified class.
 	 *
-	 * @param bm The metadata of the bean we're extending.
-	 * @throws BeanRuntimeException If any error occurred trying to construct the metadata.
+	 * @param cm The class to return the metadata on.
+	 * @return The metadata.
 	 */
-	public BeanMetaExtended(BeanMeta<?> bm) throws BeanRuntimeException {
-		this.bm = bm;
-	}
+	XmlClassMeta getXmlClassMeta(ClassMeta<?> cm);
 
 	/**
-	 * Returns the bean metadata that was passed into the constructor.
+	 * Returns the language-specific metadata on the specified bean.
 	 *
-	 * @return The bean metadata that was passed into the constructor.
+	 * @param bm The bean to return the metadata on.
+	 * @return The metadata.
 	 */
-	protected BeanMeta<?> getBeanMeta() {
-		return bm;
-	}
+	XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm);
+
+	/**
+	 * Returns the language-specific metadata on the specified bean property.
+	 *
+	 * @param bpm The bean property to return the metadata on.
+	 * @return The metadata.
+	 */
+	XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm);
 }
diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParser.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParser.java
index 642b569..508bdaa 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParser.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParser.java
@@ -12,6 +12,9 @@
 // ***************************************************************************************************************************

 package org.apache.juneau.xml;

 

+import java.util.*;

+import java.util.concurrent.*;

+

 import javax.xml.stream.*;

 import javax.xml.stream.util.*;

 

@@ -31,7 +34,7 @@
  * See the {@link XmlSerializer} class for a description of Juneau-generated XML.

  */

 @ConfigurableContext

-public class XmlParser extends ReaderParser {

+public class XmlParser extends ReaderParser implements XmlMetaProvider {

 

 	//-------------------------------------------------------------------------------------------------------------------

 	// Configurable properties

@@ -197,6 +200,9 @@
 	private final XMLReporter reporter;

 	private final XMLResolver resolver;

 	private final XMLEventAllocator eventAllocator;

+	private final Map<ClassMeta<?>,XmlClassMeta> xmlClassMetas = new ConcurrentHashMap<>();

+	private final Map<BeanMeta<?>,XmlBeanMeta> xmlBeanMetas = new ConcurrentHashMap<>();

+	private final Map<BeanPropertyMeta,XmlBeanPropertyMeta> xmlBeanPropertyMetas = new ConcurrentHashMap<>();

 

 	/**

 	 * Constructor.

@@ -257,6 +263,41 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	@Override /* XmlMetaProvider */

+	public XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) {

+		XmlClassMeta m = xmlClassMetas.get(cm);

+		if (m == null) {

+			m = new XmlClassMeta(cm, this);

+			xmlClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	@Override /* XmlMetaProvider */

+	public XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) {

+		XmlBeanMeta m = xmlBeanMetas.get(bm);

+		if (m == null) {

+			m = new XmlBeanMeta(bm, this);

+			xmlBeanMetas.put(bm, m);

+		}

+		return m;

+	}

+

+	@Override /* XmlMetaProvider */

+	public XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		XmlBeanPropertyMeta m = xmlBeanPropertyMetas.get(bpm);

+		if (m == null) {

+			BeanPropertyMeta dbpm = bpm.getDelegateFor();

+			m = new XmlBeanPropertyMeta(dbpm, this);

+			xmlBeanPropertyMetas.put(bpm, m);

+		}

+		return m;

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Properties

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java
index 872a1e8..0723260 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlParserSession.java
@@ -357,10 +357,10 @@
 		} else if (sType.isNumber()) {

 			o = parseNumber(getElementText(r), (Class<? extends Number>)sType.getInnerClass());

 		} else if (builder != null || sType.canCreateNewBean(outer)) {

-			if (sType.getExtendedMeta(XmlClassMeta.class).getFormat() == COLLAPSED) {

+			if (getXmlClassMeta(sType).getFormat() == COLLAPSED) {

 				String fieldName = r.getLocalName();

 				BeanMap<?> m = builder != null ? toBeanMap(builder.create(this, eType)) : newBeanMap(outer, sType.getInnerClass());

-				BeanPropertyMeta bpm = m.getMeta().getExtendedMeta(XmlBeanMeta.class).getPropertyMeta(fieldName);

+				BeanPropertyMeta bpm = getXmlBeanMeta(m.getMeta()).getPropertyMeta(fieldName);

 				ClassMeta<?> cm = m.getMeta().getClassMeta();

 				Object value = parseAnything(cm, currAttr, r, m.getBean(false), false, null);

 				setName(cm, value, currAttr);

@@ -472,7 +472,7 @@
 

 	private <T> BeanMap<T> parseIntoBean(XmlReader r, BeanMap<T> m, boolean isNil) throws IOException, ParseException, ExecutableException, XMLStreamException {

 		BeanMeta<?> bMeta = m.getMeta();

-		XmlBeanMeta xmlMeta = bMeta.getExtendedMeta(XmlBeanMeta.class);

+		XmlBeanMeta xmlMeta = getXmlBeanMeta(bMeta);

 

 		for (int i = 0; i < r.getAttributeCount(); i++) {

 			String key = getAttributeName(r, i);

@@ -567,7 +567,7 @@
 						skipCurrentTag(r);

 					} else {

 						setCurrentProperty(pMeta);

-						XmlFormat xf = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getXmlFormat();

+						XmlFormat xf = getXmlBeanPropertyMeta(pMeta).getXmlFormat();

 						if (xf == COLLAPSED) {

 							ClassMeta<?> et = pMeta.getClassMeta().getElementType();

 							Object value = parseAnything(et, currAttr, r, m.getBean(false), false, pMeta);

@@ -763,6 +763,40 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	/**

+	 * Returns the language-specific metadata on the specified class.

+	 *

+	 * @param cm The class to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) {

+		return ctx.getXmlClassMeta(cm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean.

+	 *

+	 * @param bm The bean to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) {

+		return ctx.getXmlBeanMeta(bm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean property.

+	 *

+	 * @param bpm The bean property to return the metadata on.

+	 * @return The metadata.

+	 */

+	protected XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		return ctx.getXmlBeanPropertyMeta(bpm);

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
index 4bc8c27..095b967 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializer.java
@@ -12,6 +12,9 @@
 // ***************************************************************************************************************************

 package org.apache.juneau.xml;

 

+import java.util.*;

+import java.util.concurrent.*;

+

 import org.apache.juneau.*;

 import org.apache.juneau.annotation.*;

 import org.apache.juneau.json.*;

@@ -111,7 +114,7 @@
  * </ul>

  */

 @ConfigurableContext

-public class XmlSerializer extends WriterSerializer {

+public class XmlSerializer extends WriterSerializer implements XmlMetaProvider {

 

 	//-------------------------------------------------------------------------------------------------------------------

 	// Configurable properties

@@ -455,6 +458,9 @@
 	private final Namespace

 		xsNamespace;

 	private final Namespace[] namespaces;

+	private final Map<ClassMeta<?>,XmlClassMeta> xmlClassMetas = new ConcurrentHashMap<>();

+	private final Map<BeanMeta<?>,XmlBeanMeta> xmlBeanMetas = new ConcurrentHashMap<>();

+	private final Map<BeanPropertyMeta,XmlBeanPropertyMeta> xmlBeanPropertyMetas = new ConcurrentHashMap<>();

 

 	private volatile XmlSchemaSerializer schemaSerializer;

 

@@ -547,6 +553,40 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	@Override /* XmlMetaProvider */

+	public XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) {

+		XmlClassMeta m = xmlClassMetas.get(cm);

+		if (m == null) {

+			m = new XmlClassMeta(cm, this);

+			xmlClassMetas.put(cm, m);

+		}

+		return m;

+	}

+

+	@Override /* XmlMetaProvider */

+	public XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) {

+		XmlBeanMeta m = xmlBeanMetas.get(bm);

+		if (m == null) {

+			m = new XmlBeanMeta(bm, this);

+			xmlBeanMetas.put(bm, m);

+		}

+		return m;

+	}

+

+	@Override /* XmlMetaProvider */

+	public XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		XmlBeanPropertyMeta m = xmlBeanPropertyMetas.get(bpm);

+		if (m == null) {

+			m = new XmlBeanPropertyMeta(bpm.getDelegateFor(), this);

+			xmlBeanPropertyMetas.put(bpm, m);

+		}

+		return m;

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Properties

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
index fdec1e6..c515083 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xml/XmlSerializerSession.java
@@ -151,7 +151,7 @@
 		}

 

 		if (aType != null) {

-			Namespace ns = cXml(aType).getNamespace();

+			Namespace ns = getXmlClassMeta(aType).getNamespace();

 			if (ns != null) {

 				if (ns.uri != null)

 					addNamespace(ns);

@@ -170,7 +170,7 @@
 				bm = toBeanMap(o);

 			} else if (aType.isDelegate()) {

 				ClassMeta<?> innerType = ((Delegate<?>)o).getClassMeta();

-				Namespace ns = cXml(innerType).getNamespace();

+				Namespace ns = getXmlClassMeta(innerType).getNamespace();

 				if (ns != null) {

 					if (ns.uri != null)

 						addNamespace(ns);

@@ -181,7 +181,7 @@
 				if (innerType.isBean()) {

 					for (BeanPropertyMeta bpm : innerType.getBeanMeta().getPropertyMetas()) {

 						if (bpm.canRead()) {

-							ns = bpXml(bpm).getNamespace();

+							ns = getXmlBeanPropertyMeta(bpm).getNamespace();

 							if (ns != null && ns.uri != null)

 								addNamespace(ns);

 						}

@@ -208,7 +208,7 @@
 			if (bm != null) {

 				for (BeanPropertyValue p : bm.getValues(isTrimNullProperties())) {

 

-					Namespace ns = bpXml(p.getMeta()).getNamespace();

+					Namespace ns = getXmlBeanPropertyMeta(p.getMeta()).getNamespace();

 					if (ns != null && ns.uri != null)

 						addNamespace(ns);

 

@@ -340,7 +340,7 @@
 		} else if (sType.isBoolean()) {

 			type = BOOLEAN;

 		} else if (sType.isMapOrBean()) {

-			isCollapsed = cXml(sType).getFormat() == COLLAPSED;

+			isCollapsed = getXmlClassMeta(sType).getFormat() == COLLAPSED;

 			type = OBJECT;

 		} else if (sType.isCollectionOrArray()) {

 			isCollapsed = (format == COLLAPSED && ! addNamespaceUris);

@@ -360,9 +360,9 @@
 

 		if (isEnableNamespaces()) {

 			if (elementNamespace == null)

-				elementNamespace = cXml(sType).getNamespace();

+				elementNamespace = getXmlClassMeta(sType).getNamespace();

 			if (elementNamespace == null)

-				elementNamespace = cXml(aType).getNamespace();

+				elementNamespace = getXmlClassMeta(aType).getNamespace();

 			if (elementNamespace != null && elementNamespace.uri == null)

 				elementNamespace = null;

 			if (elementNamespace == null)

@@ -488,7 +488,7 @@
 	private boolean isXmlText(XmlFormat format, ClassMeta<?> sType) {

 		if (format == XMLTEXT)

 			return true;

-		XmlClassMeta xcm = sType.getExtendedMeta(XmlClassMeta.class);

+		XmlClassMeta xcm = getXmlClassMeta(sType);

 		if (xcm == null)

 			return false;

 		return xcm.getFormat() == XMLTEXT;

@@ -533,7 +533,7 @@
 

 		List<BeanPropertyValue> lp = m.getValues(isTrimNullProperties());

 

-		XmlBeanMeta xbm = bXml(bm);

+		XmlBeanMeta xbm = getXmlBeanMeta(bm);

 

 		Set<String>

 			attrs = xbm.getAttrPropertyNames(),

@@ -563,7 +563,7 @@
 					if (canIgnoreValue(cMeta, key, value))

 						continue;

 

-					XmlBeanPropertyMeta bpXml = bpXml(pMeta);

+					XmlBeanPropertyMeta bpXml = getXmlBeanPropertyMeta(pMeta);

 					Namespace ns = (isEnableNamespaces() && bpXml.getNamespace() != elementNs ? bpXml.getNamespace() : null);

 

 					if (pMeta.isUri()  ) {

@@ -631,7 +631,7 @@
 						out.appendIf(! isCollapsed, '>').nlIf(! isMixedOrText, indent);

 					}

 

-					XmlBeanPropertyMeta bpXml = bpXml(pMeta);

+					XmlBeanPropertyMeta bpXml = getXmlBeanPropertyMeta(pMeta);

 					serializeAnything(out, value, cMeta, key, bpXml.getNamespace(), false, bpXml.getXmlFormat(), isMixedOrText, false, pMeta);

 				}

 			}

@@ -679,7 +679,7 @@
 		Namespace eNs = null;

 

 		if (ppMeta != null) {

-			XmlBeanPropertyMeta bpXml = bpXml(ppMeta);

+			XmlBeanPropertyMeta bpXml = getXmlBeanPropertyMeta(ppMeta);

 			eName = bpXml.getChildName();

 			eNs = bpXml.getNamespace();

 		}

@@ -691,18 +691,6 @@
 		return out;

 	}

 

-	private static XmlClassMeta cXml(ClassMeta<?> cm) {

-		return cm.getExtendedMeta(XmlClassMeta.class);

-	}

-

-	private static XmlBeanPropertyMeta bpXml(BeanPropertyMeta pMeta) {

-		return pMeta == null ? XmlBeanPropertyMeta.DEFAULT : pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);

-	}

-

-	private static XmlBeanMeta bXml(BeanMeta bm) {

-		return (XmlBeanMeta)bm.getExtendedMeta(XmlBeanMeta.class);

-	}

-

 	static enum JsonType {

 		STRING("string"),BOOLEAN("boolean"),NUMBER("number"),ARRAY("array"),OBJECT("object"),NULL("null");

 

@@ -820,6 +808,40 @@
 	}

 

 	//-----------------------------------------------------------------------------------------------------------------

+	// Extended metadata

+	//-----------------------------------------------------------------------------------------------------------------

+

+	/**

+	 * Returns the language-specific metadata on the specified class.

+	 *

+	 * @param cm The class to return the metadata on.

+	 * @return The metadata.

+	 */

+	public XmlClassMeta getXmlClassMeta(ClassMeta<?> cm) {

+		return ctx.getXmlClassMeta(cm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean.

+	 *

+	 * @param bm The bean to return the metadata on.

+	 * @return The metadata.

+	 */

+	public XmlBeanMeta getXmlBeanMeta(BeanMeta<?> bm) {

+		return ctx.getXmlBeanMeta(bm);

+	}

+

+	/**

+	 * Returns the language-specific metadata on the specified bean property.

+	 *

+	 * @param bpm The bean property to return the metadata on.

+	 * @return The metadata.

+	 */

+	public XmlBeanPropertyMeta getXmlBeanPropertyMeta(BeanPropertyMeta bpm) {

+		return bpm == null ? XmlBeanPropertyMeta.DEFAULT : ctx.getXmlBeanPropertyMeta(bpm);

+	}

+

+	//-----------------------------------------------------------------------------------------------------------------

 	// Other methods

 	//-----------------------------------------------------------------------------------------------------------------

 

diff --git a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xmlschema/XmlSchemaSerializerSession.java b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xmlschema/XmlSchemaSerializerSession.java
index 4ac369a..e451ea4 100644
--- a/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xmlschema/XmlSchemaSerializerSession.java
+++ b/juneau-core/juneau-marshall/src/main/java/org/apache/juneau/xmlschema/XmlSchemaSerializerSession.java
@@ -175,7 +175,7 @@
 			if (cm == null)
 				queueElement(ns, "null", object());
 			else {
-				XmlClassMeta xmlMeta = cm.getExtendedMeta(XmlClassMeta.class);
+				XmlClassMeta xmlMeta = getXmlClassMeta(cm);
 				if (cm.getDictionaryName() != null && xmlMeta.getNamespace() != null)
 					ns = xmlMeta.getNamespace();
 				queueElement(ns, cm.getDictionaryName(), cm);
@@ -277,7 +277,7 @@
 			ClassMeta<?> ft = cm.getSerializedClassMeta(schemas.session);
 			if (name == null)
 				name = getElementName(ft);
-			Namespace ns = first(ft.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
+			Namespace ns = first(getXmlClassMeta(ft).getNamespace(), defaultNs);
 			String type = getXmlType(ns, ft);
 
 			w.oTag(indent+1, "element")
@@ -316,7 +316,7 @@
 			while (cm.isOptional())
 				cm = cm.getElementType();
 
-			XmlBeanMeta xbm = cm.isBean() ? cm.getBeanMeta().getExtendedMeta(XmlBeanMeta.class) : null;
+			XmlBeanMeta xbm = cm.isBean() ? getXmlBeanMeta(cm.getBeanMeta()) : null;
 
 			w.oTag(i, "complexType")
 				.attr("name", name);
@@ -344,7 +344,7 @@
 
 					for (BeanPropertyMeta pMeta : bm.getPropertyMetas()) {
 						if (pMeta.canRead()) {
-							XmlFormat bpXml = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getXmlFormat();
+							XmlFormat bpXml = getXmlBeanPropertyMeta(pMeta).getXmlFormat();
 							if (bpXml == ATTRS)
 								hasAnyAttrs = true;
 							else if (bpXml != XmlFormat.ATTR)
@@ -352,7 +352,7 @@
 						}
 					}
 
-					XmlBeanMeta xbm2 = bm.getExtendedMeta(XmlBeanMeta.class);
+					XmlBeanMeta xbm2 = getXmlBeanMeta(bm);
 					if (xbm2.getContentProperty() != null && xbm2.getContentFormat() == ELEMENTS) {
 						w.sTag(i+1, "sequence").nl(i+1);
 						w.oTag(i+2, "any")
@@ -368,11 +368,11 @@
 
 						for (BeanPropertyMeta pMeta : bm.getPropertyMetas()) {
 							if (pMeta.canRead()) {
-								XmlBeanPropertyMeta xmlMeta = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
+								XmlBeanPropertyMeta xmlMeta = getXmlBeanPropertyMeta(pMeta);
 								if (xmlMeta.getXmlFormat() != ATTR) {
 									if (xmlMeta.getNamespace() != null) {
 										ClassMeta<?> ct2 = pMeta.getClassMeta();
-										Namespace cNs = first(xmlMeta.getNamespace(), ct2.getExtendedMeta(XmlClassMeta.class).getNamespace(), cm.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
+										Namespace cNs = first(xmlMeta.getNamespace(), getXmlClassMeta(ct2).getNamespace(), getXmlClassMeta(cm).getNamespace(), defaultNs);
 										// Child element is in another namespace.
 										schemas.queueElement(cNs, pMeta.getName(), ct2);
 										hasOtherNsElement = true;
@@ -399,7 +399,7 @@
 							w.sTag(i+1, "all").nl(i+1);
 							for (BeanPropertyMeta pMeta : bm.getPropertyMetas()) {
 								if (pMeta.canRead()) {
-									XmlBeanPropertyMeta xmlMeta = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class);
+									XmlBeanPropertyMeta xmlMeta = getXmlBeanPropertyMeta(pMeta);
 									if (xmlMeta.getXmlFormat() != ATTR) {
 										boolean isCollapsed = xmlMeta.getXmlFormat() == COLLAPSED;
 										ClassMeta<?> ct2 = pMeta.getClassMeta();
@@ -409,7 +409,7 @@
 												childName = xmlMeta.getChildName();
 											ct2 = pMeta.getClassMeta().getElementType();
 										}
-										Namespace cNs = first(xmlMeta.getNamespace(), ct2.getExtendedMeta(XmlClassMeta.class).getNamespace(), cm.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
+										Namespace cNs = first(xmlMeta.getNamespace(), getXmlClassMeta(ct2).getNamespace(), getXmlClassMeta(cm).getNamespace(), defaultNs);
 										if (xmlMeta.getNamespace() == null) {
 											w.oTag(i+2, "element")
 												.attr("name", XmlUtils.encodeElementName(childName), false)
@@ -430,9 +430,9 @@
 
 					}
 
-					for (BeanPropertyMeta pMeta : bm.getExtendedMeta(XmlBeanMeta.class).getAttrProperties().values()) {
+					for (BeanPropertyMeta pMeta : getXmlBeanMeta(bm).getAttrProperties().values()) {
 						if (pMeta.canRead()) {
-							Namespace pNs = pMeta.getExtendedMeta(XmlBeanPropertyMeta.class).getNamespace();
+							Namespace pNs = getXmlBeanPropertyMeta(pMeta).getNamespace();
 							if (pNs == null)
 								pNs = defaultNs;
 
@@ -470,7 +470,7 @@
 							.ceTag().nl(i+2);
 						w.eTag(i+1, "sequence").nl(i+1);
 					} else {
-						Namespace cNs = first(elementType.getExtendedMeta(XmlClassMeta.class).getNamespace(), cm.getExtendedMeta(XmlClassMeta.class).getNamespace(), defaultNs);
+						Namespace cNs = first(getXmlClassMeta(elementType).getNamespace(), getXmlClassMeta(cm).getNamespace(), defaultNs);
 						schemas.queueType(cNs, null, elementType);
 						w.sTag(i+1, "sequence").nl(i+1);
 						w.oTag(i+2, "any")