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

umich.ms.fileio.util.jaxb.JaxbUtils Maven / Gradle / Ivy

There is a newer version: 1.8.8
Show newest version
/*
 * Copyright 2016 Dmitry Avtonomov.
 *
 * 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 umich.ms.fileio.util.jaxb;

import javax.xml.bind.*;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.XMLStreamReader;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import java.io.*;
import java.lang.ref.SoftReference;
import java.nio.file.Path;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * Generic serializer (marshaller/unmarshaller) class that uses JAXB.
 *
 * @see JAXB
 *
 * @author Arno Moonen 
 * @author Dmitry Avtonomov
 */
@SuppressWarnings({"rawtypes", "unchecked"})
public class JaxbUtils
{
    /**
     * To improve the performance, we'll cache the last {@link JAXBContext} used.
     */
    protected static final class Cache {
        final Class type;
        final JAXBContext context;

        public Cache(Class type) throws JAXBException {
            this.type = type;
            this.context = JAXBContext.newInstance(type);
        }
    }

    /**
     * Cache. We don't want to prevent the {@link JaxbUtils.Cache} from being GC-ed,
     * hence {@link SoftReference}.
     */
    protected static volatile SoftReference CACHE;

    /**
     * Obtains the {@link JAXBContext} from the given type, by using the cache if possible.
     * 

* The original code in {@link JAXB} class claimed that {@code volatile} on the {@code WeakReference} variable * that they stored the cache in was enough to provide thread safety, but I don't think so as the reference itself, * inside the {@code WeakReference} wrapper isn't volatile. *

* My improvement * */ private synchronized static JAXBContext getContext(Class type) throws JAXBException { final SoftReference existingCacheRef= CACHE; if (existingCacheRef != null) { Cache existingCache = existingCacheRef.get(); if(existingCache != null && existingCache.type == type) return existingCache.context; } // overwrite the cache Cache newCache = new Cache(type); CACHE = new SoftReference(newCache); return newCache.context; } /** * Creates an XMLStreamReader based on a file path. * * @param path the path to the file to be parsed * @param namespaceAware if {@code false} the XMLStreamReader will remove all namespaces from all XML elements * @return platform-specific XMLStreamReader implementation * @throws JAXBException if the XMLStreamReader could not be created */ public static XMLStreamReader createXmlStreamReader(Path path, boolean namespaceAware) throws JAXBException { XMLInputFactory xif = getXmlInputFactory(namespaceAware); XMLStreamReader xsr = null; try { xsr = xif.createXMLStreamReader(new StreamSource(path.toFile())); } catch (XMLStreamException e) { throw new JAXBException(e); } return xsr; } /** * Creates an XMLStreamReader based on an input stream. * * @param is the input stream from which the data to be parsed will be taken * @param namespaceAware if {@code false} the XMLStreamReader will remove all namespaces from all XML elements * @return platform-specific XMLStreamReader implementation * @throws JAXBException if the XMLStreamReader could not be created */ public static XMLStreamReader createXmlStreamReader(InputStream is, boolean namespaceAware) throws JAXBException { XMLInputFactory xif = getXmlInputFactory(namespaceAware); XMLStreamReader xsr = null; try { xsr = xif.createXMLStreamReader(is); } catch (XMLStreamException e) { throw new JAXBException(e); } return xsr; } /** * Creates an XMLStreamReader based on a Reader. * * @param reader Note that XMLStreamReader, despite the name, does not implement the Reader interface! * @param namespaceAware if {@code false} the XMLStreamReader will remove all namespaces from all XML elements * @return platform-specific XMLStreamReader implementation * @throws JAXBException if the XMLStreamReader could not be created */ public static XMLStreamReader createXmlStreamReader(Reader reader, boolean namespaceAware) throws JAXBException { XMLInputFactory xif = getXmlInputFactory(namespaceAware); XMLStreamReader xsr = null; try { xsr = xif.createXMLStreamReader(reader); } catch (XMLStreamException e) { throw new JAXBException(e); } return xsr; } protected static XMLInputFactory getXmlInputFactory(boolean namespaceAware) throws JAXBException { XMLInputFactory xif = XMLInputFactory.newFactory(); if (!namespaceAware) { if (!xif.isPropertySupported(XMLInputFactory.IS_NAMESPACE_AWARE)) throw new JAXBException( "The XMLInputFactory on this system does not support non-namespace aware parsing. " + "Look at the source of 'umich.ms.fileio.filetypes.pepxml.PepXmlParser#parse(Path) " + "method as a reference to implement something else :)"); xif.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, false); } return xif; } public static T unmarshall(Class clazz, XMLStreamReader xsr) throws JAXBException { JAXBContext jaxb = getContext(clazz); Unmarshaller unmarshaller = jaxb.createUnmarshaller(); JAXBElement jaxbElement = unmarshaller.unmarshal(xsr, clazz); return jaxbElement.getValue(); } public static T unmarshall(Class clazz, XMLStreamReader xsr, Unmarshaller unmarshaller) throws JAXBException { JAXBElement jaxbElement = unmarshaller.unmarshal(xsr, clazz); return jaxbElement.getValue(); } /** * Convert a string to an object of a given class. * * @param cl Type of object * @param s Input string * @return Object of the given type * @throws JAXBException */ public static T unmarshal(Class cl, String s) throws JAXBException { return unmarshal(cl, new StringReader(s)); } /** * Convert the contents of a file to an object of a given class. * * @param cl Type of object * @param f File to be read * @return Object of the given type * @throws JAXBException */ public static T unmarshal(Class cl, File f) throws JAXBException { return unmarshal(cl, new StreamSource(f)); } /** * Convert the contents of a Reader to an object of a given class. * * @param cl Type of object * @param r Reader to be read * @return Object of the given type * @throws JAXBException */ public static T unmarshal(Class cl, Reader r) throws JAXBException { return unmarshal(cl, new StreamSource(r)); } /** * Convert the contents of an InputStream to an object of a given * class. * * @param cl Type of object * @param s InputStream to be read * @return Object of the given type * @throws JAXBException */ public static T unmarshal(Class cl, InputStream s) throws JAXBException { return unmarshal(cl, new StreamSource(s)); } /** * Convert the contents of a Source to an object of a given class. * * @param cl Type of object * @param s Source to be used * @return Object of the given type * @throws JAXBException */ public static T unmarshal(Class cl, Source s) throws JAXBException { JAXBContext ctx = JAXBContext.newInstance(cl); Unmarshaller u = ctx.createUnmarshaller(); return u.unmarshal(s, cl).getValue(); } /** * Converts the contents of the string to a List with objects of * the given class. * * @param cl Type to be used * @param s Input string * @return List with objects of the given type * @throws JAXBException */ public static List unmarshalCollection(Class cl, String s) throws JAXBException { return unmarshalCollection(cl, new StringReader(s)); } /** * Converts the contents of the Reader to a List with objects of * the given class. * * @param cl Type to be used * @param r Input * @return List with objects of the given type * @throws JAXBException */ public static List unmarshalCollection(Class cl, Reader r) throws JAXBException { return unmarshalCollection(cl, new StreamSource(r)); } /** * Converts the contents of the InputStream to a List with objects * of the given class. * * @param cl Type to be used * @param s Input * @return List with objects of the given type * @throws JAXBException */ public static List unmarshalCollection(Class cl, InputStream s) throws JAXBException { return unmarshalCollection(cl, new StreamSource(s)); } /** * Converts the contents of the Source to a List with objects of * the given class. * * @param cl Type to be used * @param s Input * @return List with objects of the given type * @throws JAXBException */ public static List unmarshalCollection(Class cl, Source s) throws JAXBException { JAXBContext ctx = JAXBContext.newInstance(JAXBCollection.class, cl); Unmarshaller u = ctx.createUnmarshaller(); JAXBCollection collection = u.unmarshal(s, JAXBCollection.class).getValue(); return collection.getItems(); } /** * Convert an object to a string. * * @param obj Object that needs to be serialized / marshalled. * @return String representation of obj * @throws JAXBException */ public static String marshal(T obj) throws JAXBException { StringWriter sw = new StringWriter(); marshal(obj, sw); return sw.toString(); } /** * Convert an object to a string and send it to a Writer. * * @param obj Object that needs to be serialized / marshalled * @param wr Writer used for outputting the marshalled object * @throws JAXBException */ public static void marshal(T obj, Writer wr) throws JAXBException { JAXBContext ctx = JAXBContext.newInstance(obj.getClass()); Marshaller m = ctx.createMarshaller(); m.marshal(obj, wr); } /** * Convert an object to a string and save it to a File. * * @param obj Object that needs to be serialized / marshalled * @param f Save file * @throws JAXBException */ public static void marshal(T obj, File f) throws JAXBException { JAXBContext ctx = JAXBContext.newInstance(obj.getClass()); Marshaller m = ctx.createMarshaller(); m.marshal(obj, f); } /** * Convert an object to a string and send it to an OutputStream. * * @param obj Object that needs to be serialized / marshalled * @param s Stream used for output * @throws JAXBException */ public static void marshal(T obj, OutputStream s) throws JAXBException { JAXBContext ctx = JAXBContext.newInstance(obj.getClass()); Marshaller m = ctx.createMarshaller(); m.marshal(obj, s); } /** * Convert a collection to a string. * * @param rootName Name of the XML root element * @param c Collection that needs to be marshalled * @return String representation of the collection * @throws JAXBException */ public static String marshal(String rootName, Collection c) throws JAXBException { StringWriter sw = new StringWriter(); marshal(rootName, c, sw); return sw.toString(); } /** * Convert a collection to a string and sends it to the Writer. * * @param rootName Name of the XML root element * @param c Collection that needs to be marshalled * @param w Output * @throws JAXBException */ public static void marshal(String rootName, Collection c, Writer w) throws JAXBException { // Create context with generic type JAXBContext ctx = JAXBContext.newInstance(findTypes(c)); Marshaller m = ctx.createMarshaller(); // Create wrapper collection JAXBElement element = createCollectionElement(rootName, c); m.marshal(element, w); } /** * Convert a collection to a string and stores it in a File. * * @param rootName Name of the XML root element * @param c Collection that needs to be marshalled * @param f Output file * @throws JAXBException */ public static void marshal(String rootName, Collection c, File f) throws JAXBException { // Create context with generic type JAXBContext ctx = JAXBContext.newInstance(findTypes(c)); Marshaller m = ctx.createMarshaller(); // Create wrapper collection JAXBElement element = createCollectionElement(rootName, c); m.marshal(element, f); } /** * Convert a collection to a string and sends it to the * OutputStream. * * @param rootName Name of the XML root element * @param c Collection that needs to be marshalled * @param s Output * @throws JAXBException */ public static void marshal(String rootName, Collection c, OutputStream s) throws JAXBException { // Create context with generic type JAXBContext ctx = JAXBContext.newInstance(findTypes(c)); Marshaller m = ctx.createMarshaller(); // Create wrapper collection JAXBElement element = createCollectionElement(rootName, c); m.marshal(element, s); } /** * Discovers all the classes in the given Collection. These need * to be in the JAXBContext if you want to marshal those objects. * Unfortunatly there's no way of getting the generic type at * runtime. * * @param c Collection that needs to be scanned * @return Classes found in the collection, including * JAXBCollection. */ protected static Class[] findTypes(Collection c) { Set types = new HashSet(); types.add(JAXBCollection.class); for (T o : c) { if (o != null) { types.add(o.getClass()); } } return types.toArray(new Class[0]); } /** * Create a JAXBElement containing a JAXBCollection. Needed for * marshalling a generic collection without a seperate wrapper * class. * * @param rootName Name of the XML root element * @param c * @return JAXBElement containing the given Collection, wrapped in * a JAXBCollection. */ protected static JAXBElement createCollectionElement(String rootName, Collection c) { JAXBCollection collection = new JAXBCollection(c); return new JAXBElement(new QName(rootName), JAXBCollection.class, collection); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy