org.openlegacy.utils.XmlSerializationUtil.java Source code

Java tutorial

Introduction

Here is the source code for org.openlegacy.utils.XmlSerializationUtil.java

Source

/*******************************************************************************
 * Copyright (c) 2014 OpenLegacy Inc.
 * All rights reserved. This program and the accompanying materials 
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     OpenLegacy Inc. - initial API and implementation
 *******************************************************************************/
package org.openlegacy.utils;

import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.ObjectUtils;
import org.springframework.beans.DirectFieldAccessor;

import java.beans.PropertyDescriptor;
import java.io.BufferedReader;
import java.io.FilterReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.Reader;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.Map;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Marshaller.Listener;
import javax.xml.bind.Unmarshaller;

public class XmlSerializationUtil {

    public static <T> void serialize(Class<T> rootClass, T persistedObject, OutputStream out) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(rootClass);
        Marshaller marshaller = context.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
        marshaller.setListener(new Listener() {

            @Override
            public void beforeMarshal(Object source) {
                resetDefaultValues(source);
                super.beforeMarshal(source);
            }

        });
        marshaller.marshal(persistedObject, out);
    }

    @SuppressWarnings("unchecked")
    public static <T> T deserialize(Class<T> rootClass, InputStream in) throws JAXBException {
        JAXBContext context = JAXBContext.newInstance(rootClass);
        Unmarshaller unmarshaller = context.createUnmarshaller();

        Reader reader;
        try {
            reader = new InvalidXMLCharacterFilterReader(new BufferedReader(new InputStreamReader(in, "UTF-8")));
        } catch (UnsupportedEncodingException e) {
            throw (new RuntimeException(e));
        }
        return (T) unmarshaller.unmarshal(reader);
    }

    /**
     * This method purpose is to reduce the amount of XML written when serializing an object It reset member to null when the
     * default value matches the object value
     * 
     * @param source
     */
    private static void resetDefaultValues(Object source) {
        DirectFieldAccessor fieldAccessor = new DirectFieldAccessor(source);
        PropertyDescriptor[] propertyDescriptors = PropertyUtils.getPropertyDescriptors(source);
        for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
            String propertyName = propertyDescriptor.getName();
            Class<?> propertyType = fieldAccessor.getPropertyType(propertyName);
            if (propertyType == null || Collection.class.isAssignableFrom(propertyType)
                    || Map.class.isAssignableFrom(propertyType)) {
                continue;
            }
            Object defaultValue = PropertyUtil.getPropertyDefaultValue(source.getClass(), propertyName);
            Object value = fieldAccessor.getPropertyValue(propertyName);
            if (fieldAccessor.isWritableProperty(propertyName) && ObjectUtils.equals(value, defaultValue)
                    && !propertyType.isPrimitive()) {
                fieldAccessor.setPropertyValue(propertyName, null);
            }

        }
    }

    public static class InvalidXMLCharacterFilterReader extends FilterReader {

        public InvalidXMLCharacterFilterReader(Reader in) {
            super(in);
        }

        @Override
        public int read() throws IOException {
            char[] buf = new char[1];
            int result = read(buf, 0, 1);
            if (result == -1) {
                return -1;
            } else {
                return buf[0];
            }
        }

        @Override
        public int read(char[] buf, int from, int len) throws IOException {
            int count = 0;
            while (count == 0) {
                count = in.read(buf, from, len);
                if (count == -1) {
                    return -1;
                }

                int last = from;
                for (int i = from; i < from + count; i++) {
                    if (!isBadXMLChar(buf[i])) {
                        buf[last++] = buf[i];
                    } else {
                        buf[last++] = ' ';
                    }
                }

                count = last - from;
            }
            return count;
        }

        private static boolean isBadXMLChar(char c) {
            if ((c == 0x9) || (c == 0xA) || (c == 0xD) || ((c >= 0x20) && (c <= 0xD7FF))
                    || ((c >= 0xE000) && (c <= 0xFFFD)) || ((c >= 0x10000) && (c <= 0x10FFFF))) {
                return false;
            }
            return true;
        }
    }
}