All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.eclipse.persistence.jaxb.dynamic.metadata.SchemaMetadata Maven / Gradle / Ivy
/*
* Copyright (c) 2011, 2020 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Blaise Doughan - 2.2 - initial implementation
package org.eclipse.persistence.jaxb.dynamic.metadata;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import jakarta.xml.bind.JAXBException;
import javax.xml.transform.Source;
import javax.xml.transform.TransformerException;
import javax.xml.transform.stream.StreamResult;
import org.eclipse.persistence.dynamic.DynamicClassLoader;
import org.eclipse.persistence.internal.security.PrivilegedAccessHelper;
import org.eclipse.persistence.jaxb.dynamic.DynamicJAXBContextFactory;
import org.eclipse.persistence.jaxb.javamodel.JavaClass;
import org.eclipse.persistence.jaxb.javamodel.JavaModelInput;
import org.eclipse.persistence.jaxb.javamodel.xjc.XJCJavaClassImpl;
import org.eclipse.persistence.jaxb.javamodel.xjc.XJCJavaModelImpl;
import org.eclipse.persistence.jaxb.javamodel.xjc.XJCJavaModelInputImpl;
import org.eclipse.persistence.platform.xml.XMLPlatformException;
import org.eclipse.persistence.platform.xml.XMLPlatformFactory;
import org.eclipse.persistence.platform.xml.XMLTransformer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXParseException;
import com.sun.codemodel.ClassType;
import com.sun.codemodel.JCodeModel;
import com.sun.codemodel.JDefinedClass;
import com.sun.codemodel.JEnumConstant;
import com.sun.codemodel.JPackage;
import com.sun.tools.xjc.Plugin;
import com.sun.tools.xjc.api.ErrorListener;
import com.sun.tools.xjc.api.S2JJAXBModel;
import com.sun.tools.xjc.api.SchemaCompiler;
import com.sun.tools.xjc.api.XJC;
public class SchemaMetadata extends Metadata {
private static final String DEFAULT_SYSTEM_ID = "sysid";
private SchemaCompiler schemaCompiler;
private Field JDEFINEDCLASS_ENUMCONSTANTS = null;
private List externalBindings;
@SuppressWarnings("unchecked")
public SchemaMetadata(DynamicClassLoader dynamicClassLoader, Map properties) throws JAXBException {
super(dynamicClassLoader, properties);
try {
JDEFINEDCLASS_ENUMCONSTANTS = PrivilegedAccessHelper.getDeclaredField(JDefinedClass.class, "enumConstantsByName", true);
} catch (Exception e) {
throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.errorCreatingDynamicJAXBContext(e));
}
try {
if (properties != null) {
Object propValue = properties.get(DynamicJAXBContextFactory.EXTERNAL_BINDINGS_KEY);
if (propValue != null) {
externalBindings = new ArrayList();
if (propValue instanceof List>) {
List xjbSources = (List) propValue;
for (Source source : xjbSources) {
externalBindings.add(createInputSourceFromSource(source));
}
} else {
Source xjbSource = (Source) propValue;
InputSource xjbInputSource = createInputSourceFromSource(xjbSource);
externalBindings.add(xjbInputSource);
}
}
}
} catch (ClassCastException cce) {
throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.xjbNotSource());
}
}
public SchemaMetadata(DynamicClassLoader dynamicClassLoader, Map properties, Source metadataSource, EntityResolver resolver) throws JAXBException {
this(dynamicClassLoader, properties);
try {
InputSource schemaInputSource = createInputSourceFromSource(metadataSource);
if (schemaInputSource.getSystemId() == null) {
schemaInputSource.setSystemId(DEFAULT_SYSTEM_ID);
}
// Use XJC API to parse the schema and generate its JCodeModel
schemaCompiler = XJC.createSchemaCompiler();
schemaCompiler.setEntityResolver(resolver);
schemaCompiler.setErrorListener(new XJCErrorListener());
if (externalBindings != null) {
for (InputSource xjbSource : externalBindings) {
schemaCompiler.parseSchema(xjbSource);
}
}
schemaCompiler.parseSchema(schemaInputSource);
} catch (XMLPlatformException xpe) {
// This will occur when trying to refreshMetadata from a closed stream (non-XML Node metadata)
if (xpe.getCause() instanceof TransformerException) {
TransformerException te = (TransformerException) xpe.getCause();
if (te.getCause() instanceof IOException) {
throw org.eclipse.persistence.exceptions.JAXBException.cannotRefreshMetadata();
}
}
} catch (Exception e) {
throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.errorCreatingDynamicJAXBContext(e));
}
}
public SchemaMetadata(DynamicClassLoader dynamicClassLoader, Map properties, Node node, EntityResolver resolver) throws JAXBException {
this(dynamicClassLoader, properties);
Element element;
if (node.getNodeType() == Node.DOCUMENT_NODE) {
element = ((Document) node).getDocumentElement();
} else if (node.getNodeType() == Node.ELEMENT_NODE) {
element = (Element) node;
} else {
throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.cannotInitializeFromNode());
}
// Use XJC API to parse the schema and generate its JCodeModel
schemaCompiler = XJC.createSchemaCompiler();
schemaCompiler.setEntityResolver(resolver);
schemaCompiler.setErrorListener(new XJCErrorListener());
schemaCompiler.parseSchema(DEFAULT_SYSTEM_ID, element);
}
@Override
public JavaModelInput getJavaModelInput() throws JAXBException {
S2JJAXBModel model = schemaCompiler.bind();
if (model == null) {
throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.xjcBindingError());
}
JCodeModel codeModel = model.generateCode(new Plugin[0], null);
// Create EclipseLink JavaModel objects for each of XJC's JDefinedClasses
ArrayList classesToProcess = new ArrayList();
Iterator packages = codeModel.packages();
while (packages.hasNext()) {
JPackage pkg = packages.next();
Iterator classes = pkg.classes();
while (classes.hasNext()) {
JDefinedClass cls = classes.next();
classesToProcess.add(cls);
}
}
// Look for Inner Classes and add them
ArrayList innerClasses = new ArrayList();
for (int i = 0; i < classesToProcess.size(); i++) {
innerClasses.addAll(getInnerClasses(classesToProcess.get(i)));
}
classesToProcess.addAll(innerClasses);
JavaClass[] jotClasses = createClassModelFromXJC(classesToProcess, codeModel, dynamicClassLoader);
// Use the JavaModel to setup a Generator to generate an EclipseLink project
XJCJavaModelImpl javaModel = new XJCJavaModelImpl(codeModel, dynamicClassLoader);
XJCJavaModelInputImpl javaModelInput = new XJCJavaModelInputImpl(jotClasses, javaModel);
for (JavaClass javaClass : jotClasses) {
((XJCJavaClassImpl) javaClass).setJavaModel(javaModel);
javaModel.getJavaModelClasses().put(javaClass.getQualifiedName(), javaClass);
}
return javaModelInput;
}
private HashSet getInnerClasses(JDefinedClass xjcClass) {
// Check this xjcClass for inner classes. If one is found, search that one too.
HashSet classesToReturn = new HashSet();
Iterator it = xjcClass.classes();
while (it.hasNext()) {
JDefinedClass innerClass = it.next();
classesToReturn.add(innerClass);
classesToReturn.addAll(getInnerClasses(innerClass));
}
return classesToReturn;
}
@SuppressWarnings("unchecked")
private JavaClass[] createClassModelFromXJC(ArrayList xjcClasses, JCodeModel jCodeModel, DynamicClassLoader dynamicClassLoader) throws JAXBException {
try {
JavaClass[] elinkClasses = new JavaClass[xjcClasses.size()];
int count = 0;
for (JDefinedClass definedClass : xjcClasses) {
XJCJavaClassImpl xjcClass = new XJCJavaClassImpl(definedClass, jCodeModel, dynamicClassLoader);
elinkClasses[count] = xjcClass;
count++;
// If this is an enum, trigger a dynamic class generation, because we won't
// be creating a descriptor for it
if (definedClass.getClassType().equals(ClassType.ENUM)) {
Map enumConstants = (Map) PrivilegedAccessHelper.getValueFromField(JDEFINEDCLASS_ENUMCONSTANTS, definedClass);
Object[] enumValues = enumConstants.keySet().toArray();
dynamicClassLoader.addEnum(definedClass.fullName(), enumValues);
}
}
return elinkClasses;
} catch (Exception e) {
throw new JAXBException(org.eclipse.persistence.exceptions.JAXBException.errorCreatingDynamicJAXBContext(e));
}
}
private static InputSource createInputSourceFromSource(Source aSource) {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
StreamResult result = new StreamResult(baos);
XMLTransformer t = XMLPlatformFactory.getInstance().getXMLPlatform().newXMLTransformer();
t.transform(aSource, result);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
InputSource inputSource = new InputSource(bais);
inputSource.setSystemId(aSource.getSystemId());
return inputSource;
}
private class XJCErrorListener implements ErrorListener {
@Override
public void error(SAXParseException arg0) {
throw org.eclipse.persistence.exceptions.JAXBException.errorCreatingDynamicJAXBContext(arg0);
}
@Override
public void fatalError(SAXParseException arg0) {
throw org.eclipse.persistence.exceptions.JAXBException.errorCreatingDynamicJAXBContext(arg0);
}
@Override
public void info(SAXParseException arg0) {
throw org.eclipse.persistence.exceptions.JAXBException.errorCreatingDynamicJAXBContext(arg0);
}
@Override
public void warning(SAXParseException arg0) {
throw org.eclipse.persistence.exceptions.JAXBException.errorCreatingDynamicJAXBContext(arg0);
}
}
}