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

com.avides.xpath.utils.XPathUnmarshaller Maven / Gradle / Ivy

The newest version!
package com.avides.xpath.utils;

import static com.avides.xpath.utils.utils.ReflectionUtils.doWithFields;

import java.io.File;
import java.io.InputStream;
import java.io.Reader;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZonedDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.avides.xpath.utils.annotations.XPathFirst;
import com.avides.xpath.utils.annotations.XPathList;
import com.avides.xpath.utils.annotations.XPathMap;
import com.avides.xpath.utils.converters.ToBooleanConverter;
import com.avides.xpath.utils.converters.ToCharacterConverter;
import com.avides.xpath.utils.converters.ToDoubleConverter;
import com.avides.xpath.utils.converters.ToFloatConverter;
import com.avides.xpath.utils.converters.ToIntegerConverter;
import com.avides.xpath.utils.converters.ToLocalDateConverter;
import com.avides.xpath.utils.converters.ToLocalDateTimeConverter;
import com.avides.xpath.utils.converters.ToLocalTimeConverter;
import com.avides.xpath.utils.converters.ToLongConverter;
import com.avides.xpath.utils.converters.ToShortConverter;
import com.avides.xpath.utils.converters.ToZonedDateTimeConverter;
import com.avides.xpath.utils.processors.XPathFirstProcessor;
import com.avides.xpath.utils.processors.XPathListProcessor;
import com.avides.xpath.utils.processors.XPathMapProcessor;

import nu.xom.Element;
import nu.xom.ParsingException;

/**
 * Class for unmarshalling xml to new instances of classes which have fields
 * that are annotated with {@link XPathFirst}, {@link XPathList} or
 * {@link XPathMap}. Such classes must have a public no-args-constructor
 *
 * @author Martin Schumacher
 * @since 1.0.0.RELEASE
 *
 * @see XPathUtils
 * @see XPathUtils#fromXml(String, Class)
 * @see XPathUtils#fromInputStream(InputStream, Class)
 * @see XPathUtils#fromReader(Reader, Class)
 * @see XPathUtils#fromFile(File, Class)
 * @see XPathUtils#fromRoot(Element, Class)
 */
public class XPathUnmarshaller
{
    private static final Logger log = LoggerFactory.getLogger(XPathUnmarshaller.class);

    private static XPathUnmarshaller instance;

    private static final Map, Function> defaultToTypeConverters = new HashMap<>();

    static
    {
        resetDefaultConverterInstancesToType();
    }

    private XPathUnmarshaller()
    {
        // private constructor to hide the public one (singleton-pattern)
    }

    /**
     * unmarshalls from xml
     *
     * @param 
     *            the type of the resulting new instance, determined by the
     *            given {@link Class}
     * @param xml
     *            xml to unmarshal from
     * @param type
     *            the type of the class with the annotated fields
     * @return new instance of the given type unmarshalled by the given xml
     * @throws ParsingException
     *             if the xml can not be parsed (invalid xml)
     *
     * @since 1.0.0.RELEASE
     */
    public  T unmarshal(String xml, Class type) throws ParsingException
    {
        return unmarshal(XPathUtils.getRootElement(xml), type);
    }

    /**
     * unmarshalls from {@link InputStream}
     *
     * @param 
     *            the type of the resulting new instance, determined by the
     *            given {@link Class}
     * @param inputStream
     *            {@link InputStream} to unmarshal from
     * @param type
     *            the type of the class with the annotated fields
     * @return new instance of the given type unmarshalled by the given
     *         {@link InputStream}
     * @throws ParsingException
     *             if the {@link InputStream} can not be parsed (invalid xml)
     *
     * @since 1.0.2.RELEASE
     */
    public  T unmarshal(InputStream inputStream, Class type) throws ParsingException
    {
        return unmarshal(XPathUtils.getRootElement(inputStream), type);
    }

    /**
     * unmarshalls from {@link Reader}
     *
     * @param 
     *            the type of the resulting new instance, determined by the
     *            given {@link Class}
     * @param reader
     *            {@link Reader} to unmarshal from
     * @param type
     *            the type of the class with the annotated fields
     * @return new instance of the given type unmarshalled by the given
     *         {@link Reader}
     * @throws ParsingException
     *             if the {@link Reader} can not be parsed (invalid xml)
     *
     * @since 1.0.2.RELEASE
     */
    public  T unmarshal(Reader reader, Class type) throws ParsingException
    {
        return unmarshal(XPathUtils.getRootElement(reader), type);
    }

    /**
     * unmarshalls from {@link File}
     *
     * @param 
     *            the type of the resulting new instance, determined by the
     *            given {@link Class}
     * @param file
     *            {@link File} to unmarshal from
     * @param type
     *            the type of the class with the annotated fields
     * @return new instance of the given type unmarshalled by the given
     *         {@link File}
     * @throws ParsingException
     *             if the {@link File} can not be parsed (invalid xml)
     *
     * @since 1.0.2.RELEASE
     */
    public  T unmarshal(File file, Class type) throws ParsingException
    {
        return unmarshal(XPathUtils.getRootElement(file), type);
    }

    /**
     * unmarshalls from {@link Element}
     *
     * @param 
     *            the type of the resulting new instance, determined by the
     *            given {@link Class}
     * @param root
     *            {@link Element} to unmarshal from
     * @param type
     *            the type of the class with the annotated fields
     * @return new instance of the given type unmarshalled by the given
     *         {@link Element}
     *
     * @since 1.0.0.RELEASE
     */
    public  T unmarshal(Element root, Class type)
    {
        final T target;

        @SuppressWarnings("unchecked") Function defaultConverter = (Function) defaultToTypeConverters.get(type);
        if (defaultConverter != null)
        {
            return defaultConverter.apply(root.getValue());
        }

        try
        {
            target = type.newInstance();
        }
        catch (InstantiationException | IllegalAccessException e)
        {
            log.error("could not create new instance for " + type.getName(), e);
            throw new RuntimeException(e);
        }
        doWithFields(type, field ->
        {
            new XPathFirstProcessor(root, field, target, defaultToTypeConverters).process();
            new XPathListProcessor(root, field, target, defaultToTypeConverters).process();
            new XPathMapProcessor(root, field, target, defaultToTypeConverters).process();
        });
        return target;
    }

    /**
     * Registers a default {@link Function Converter} to use for unmarshalling
     * when the value (after an annotated {@link Function Converter}-conversion)
     * is a {@link String} but the field-type is not. So when the registered
     * default-{@link Function Converter}s contain a matching one for the wanted
     * field-type, it is used to convert the value to the wanted type
     *
     * @param type
     *            the type that matches the field-type and the given
     *            {@link Function Converter}-result-type
     * @param converter
     *            the {@link Function Converter} to use for converting to the
     *            given type
     *
     * @since 1.0.2.RELEASE
     */
    public static void registerDefaultConverterInstanceToType(Class type, Function converter)
    {
        defaultToTypeConverters.put(type, converter);
    }

    /**
     * Unregisters a {@link Function Converter} for default-conversion for the
     * given type
     *
     * @param type
     *            the type the {@link Function Converter} is registered to
     *            convert to
     *
     * @since 1.0.3.RELEASE
     *
     * @see #registerDefaultConverterInstanceToType(Class, Function)
     */
    public static void unregisterDefaultConverterInstanceToType(Class type)
    {
        defaultToTypeConverters.remove(type);
    }

    /**
     * Resets all {@link Function Converter}s for default-conversion to the
     * default (clears all and puts the default ones)
     *
     * @since 1.0.3.RELEASE
     *
     * @see #registerDefaultConverterInstanceToType(Class, Function)
     */
    public static void resetDefaultConverterInstancesToType()
    {
        defaultToTypeConverters.clear();
        defaultToTypeConverters.put(Integer.class, XPathUtils.getConverter(ToIntegerConverter.class));
        defaultToTypeConverters.put(Long.class, XPathUtils.getConverter(ToLongConverter.class));
        defaultToTypeConverters.put(Short.class, XPathUtils.getConverter(ToShortConverter.class));
        defaultToTypeConverters.put(Double.class, XPathUtils.getConverter(ToDoubleConverter.class));
        defaultToTypeConverters.put(Float.class, XPathUtils.getConverter(ToFloatConverter.class));
        defaultToTypeConverters.put(Boolean.class, XPathUtils.getConverter(ToBooleanConverter.class));
        defaultToTypeConverters.put(Character.class, XPathUtils.getConverter(ToCharacterConverter.class));
        defaultToTypeConverters.put(int.class, XPathUtils.getConverter(ToIntegerConverter.class));
        defaultToTypeConverters.put(long.class, XPathUtils.getConverter(ToLongConverter.class));
        defaultToTypeConverters.put(short.class, XPathUtils.getConverter(ToShortConverter.class));
        defaultToTypeConverters.put(double.class, XPathUtils.getConverter(ToDoubleConverter.class));
        defaultToTypeConverters.put(float.class, XPathUtils.getConverter(ToFloatConverter.class));
        defaultToTypeConverters.put(boolean.class, XPathUtils.getConverter(ToBooleanConverter.class));
        defaultToTypeConverters.put(char.class, XPathUtils.getConverter(ToCharacterConverter.class));
        defaultToTypeConverters.put(LocalDate.class, XPathUtils.getConverter(ToLocalDateConverter.class));
        defaultToTypeConverters.put(LocalDateTime.class, XPathUtils.getConverter(ToLocalDateTimeConverter.class));
        defaultToTypeConverters.put(LocalTime.class, XPathUtils.getConverter(ToLocalTimeConverter.class));
        defaultToTypeConverters.put(ZonedDateTime.class, XPathUtils.getConverter(ToZonedDateTimeConverter.class));
    }

    /**
     * Returns the singleton-instance of the {@link XPathUnmarshaller}
     *
     * @return the singleton-instance of the {@link XPathUnmarshaller}
     *
     * @since 1.0.0.RELEASE
     */
    public static XPathUnmarshaller getInstance()
    {
        if (instance == null)
        {
            instance = new XPathUnmarshaller();
        }
        return instance;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy