com.helger.ubl20.UBL20Marshaller Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of ph-ubl20 Show documentation
Show all versions of ph-ubl20 Show documentation
Library for reading and writing UBL 2.0 documents
/**
* Copyright (C) 2014-2015 Philip Helger (www.helger.com)
* philip[at]helger[dot]com
*
* Licensed 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 com.helger.ubl20;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.MarshalException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.UnmarshalException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.namespace.QName;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.dom.DOMResult;
import javax.xml.validation.Schema;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.xml.sax.helpers.DefaultHandler;
import com.helger.commons.ValueEnforcer;
import com.helger.commons.annotation.PresentForCodeCoverage;
import com.helger.commons.debug.GlobalDebug;
import com.helger.commons.error.IResourceErrorGroup;
import com.helger.commons.state.ESuccess;
import com.helger.commons.xml.XMLFactory;
import com.helger.commons.xml.XMLHelper;
import com.helger.jaxb.JAXBMarshallerHelper;
import com.helger.jaxb.validation.CollectingValidationEventHandler;
import com.helger.ubl.api.AbstractUBLMarshaller;
/**
* This is the marshaller for UBL documents.
*
* @author Philip Helger
*/
@Immutable
public final class UBL20Marshaller extends AbstractUBLMarshaller
{
private static final Logger s_aLogger = LoggerFactory.getLogger (UBL20Marshaller.class);
@PresentForCodeCoverage
private static final UBL20Marshaller s_aInstance = new UBL20Marshaller ();
private UBL20Marshaller ()
{}
/**
* Convert the passed XML node into a domain object.
* Note: this is the generic API for reading all types of UBL documents.
* Please refer to {@link UBL20Reader} for a type-safe API for all supported
* document types.
*
* @param aNode
* The XML node to be converted. May not be null
.
* @param aClassLoader
* Optional class loader to be used for JAXBContext. May be
* null
to indicate to use the default class loader.
* @param aDestClass
* The UBL class of the result type. May not be null
.
* @param aCustomEventHandler
* An optional custom event handler to be used in unmarshalling. May
* be null
.
* @return null
in case conversion to the specified class failed.
* See the log output for details.
*/
@Nullable
public static T readUBLDocument (@Nonnull final Node aNode,
@Nullable final ClassLoader aClassLoader,
@Nonnull final Class aDestClass,
@Nullable final ValidationEventHandler aCustomEventHandler)
{
ValueEnforcer.notNull (aNode, "Node");
ValueEnforcer.notNull (aDestClass, "DestClass");
final String sNodeNamespaceURI = XMLHelper.getNamespaceURI (aNode);
final Class > aClass = UBL20DocumentTypes.getImplementationClassOfNamespace (sNodeNamespaceURI);
// Avoid class cast exception later on
if (!aDestClass.equals (aClass))
{
s_aLogger.error ("You cannot read an '" + sNodeNamespaceURI + "' as a " + aDestClass.getName ());
return null;
}
final Schema aSchema = UBL20DocumentTypes.getSchemaOfNamespace (sNodeNamespaceURI, aClassLoader);
if (aSchema == null)
throw new IllegalStateException ("Internal inconsistency. Failed to resolve namespace URI '" +
sNodeNamespaceURI +
"'");
T ret = null;
try
{
final Unmarshaller aUnmarshaller = createFullUnmarshaller (aClass, aClassLoader, aSchema, aCustomEventHandler);
// start unmarshalling
ret = aUnmarshaller.unmarshal (aNode, aDestClass).getValue ();
if (ret == null)
throw new IllegalStateException ("Failed to read UBL 2.0 document of class " +
aDestClass.getName () +
" - without exception!");
}
catch (final UnmarshalException ex)
{
// The JAXB specification does not mandate how the JAXB provider
// must behave when attempting to unmarshal invalid XML data. In
// those cases, the JAXB provider is allowed to terminate the
// call to unmarshal with an UnmarshalException.
s_aLogger.error ("Unmarshal exception reading UBL 2.0 document", ex);
return null;
}
catch (final JAXBException ex)
{
s_aLogger.warn ("JAXB Exception reading UBL 2.0 document", ex);
return null;
}
return ret;
}
/**
* Convert the passed XML node into a domain object.
* Note: this is the generic API for reading all types of UBL documents.
* Please refer to {@link UBL20Reader} for a type-safe API for all supported
* document types.
*
* @param aSource
* The source object to be converted. May not be null
.
* @param aClassLoader
* Optional class loader to be used for JAXBContext. May be
* null
to indicate to use the default class loader.
* @param aDestClass
* The UBL class of the result type. May not be null
.
* @param aCustomEventHandler
* An optional custom event handler to be used in unmarshalling. May
* be null
.
* @return null
in case conversion to the specified class failed.
* See the log output for details.
*/
@Nullable
public static T readUBLDocument (@Nonnull final Source aSource,
@Nullable final ClassLoader aClassLoader,
@Nonnull final Class aDestClass,
@Nullable final ValidationEventHandler aCustomEventHandler)
{
ValueEnforcer.notNull (aSource, "Source");
ValueEnforcer.notNull (aDestClass, "DestClass");
// as we don't have a node, we need to trust the implementation class
final Schema aSchema = UBL20DocumentTypes.getSchemaOfImplementationClass (aDestClass, aClassLoader);
if (aSchema == null)
{
s_aLogger.error ("Don't know how to read UBL 2.0 object of class " + aDestClass.getName ());
return null;
}
T ret = null;
try
{
final Unmarshaller aUnmarshaller = createFullUnmarshaller (aDestClass,
aClassLoader,
aSchema,
aCustomEventHandler);
// start unmarshalling
ret = aUnmarshaller.unmarshal (aSource, aDestClass).getValue ();
if (ret == null)
throw new IllegalStateException ("Failed to read UBL 2.0 document of class " +
aDestClass.getName () +
" - without exception!");
}
catch (final UnmarshalException ex)
{
// The JAXB specification does not mandate how the JAXB provider
// must behave when attempting to unmarshal invalid XML data. In
// those cases, the JAXB provider is allowed to terminate the
// call to unmarshal with an UnmarshalException.
s_aLogger.error ("Unmarshal exception reading UBL 2.0 document", ex);
return null;
}
catch (final JAXBException ex)
{
s_aLogger.warn ("JAXB Exception reading UBL 2.0 document", ex);
return null;
}
return ret;
}
@Nonnull
private static Marshaller _createFullMarshaller (@Nonnull final Class > aClass,
@Nullable final ClassLoader aClassLoader,
@Nonnull final String sNamespaceURI,
@Nullable final ValidationEventHandler aCustomEventHandler) throws JAXBException
{
// Validating!
final Schema aSchema = UBL20DocumentTypes.getSchemaOfNamespace (sNamespaceURI, aClassLoader);
if (aSchema == null)
throw new IllegalArgumentException ("Don't know how to write UBL 2.0 object of class '" + sNamespaceURI + "'");
// Create a generic marshaller
final Marshaller aMarshaller = createBasicMarshaller (aClass, aClassLoader, aSchema, aCustomEventHandler);
try
{
JAXBMarshallerHelper.setSunNamespacePrefixMapper (aMarshaller, UBL20NamespaceContext.getInstance ());
}
catch (final Throwable t)
{
// Might be an IllegalArgumentException or a NoClassDefFoundError
s_aLogger.error ("Failed to set the namespace prefix mapper: " +
t.getClass ().getName () +
" -- " +
t.getMessage (),
GlobalDebug.isDebugMode () ? t.getCause () : null);
}
return aMarshaller;
}
@SuppressWarnings ("unchecked")
@Nonnull
private static JAXBElement > _createJAXBElement (@Nonnull final QName aQName, @Nonnull final Object aValue)
{
return new JAXBElement