com.github.yihtserns.jaxbean.unmarshaller.JaxbeanUnmarshaller.java Source code

Java tutorial

Introduction

Here is the source code for com.github.yihtserns.jaxbean.unmarshaller.JaxbeanUnmarshaller.java

Source

/*
 * Copyright 2015 The Apache Software Foundation.
 *
 * 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.github.yihtserns.jaxbean.unmarshaller;

import com.github.yihtserns.jaxbean.unmarshaller.api.BeanHandler;
import com.github.yihtserns.jaxbean.unmarshaller.Unmarshaller.InitializableElementUnmarshaller;
import com.github.yihtserns.jaxbean.unmarshaller.Unmarshaller.ElementUnmarshallerProvider;
import com.github.yihtserns.jaxbean.unmarshaller.Unmarshaller.ElementUnmarshallerProvider.Handler;
import java.beans.Introspector;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import org.springframework.beans.BeanWrapper;
import org.springframework.beans.PropertyAccessorFactory;
import org.w3c.dom.Element;

/**
 *
 * @author yihtserns
 */
public class JaxbeanUnmarshaller {

    private Map<String, Unmarshaller<Element>> globalName2Unmarshaller;

    /**
     * @see #newInstance(java.lang.Class...)
     */
    private JaxbeanUnmarshaller(Map<String, Unmarshaller<Element>> globalName2Unmarshaller) {
        this.globalName2Unmarshaller = globalName2Unmarshaller;
    }

    public Object unmarshal(Element element) throws Exception {
        return unmarshal(element, ObjectBeanHandler.INSTANCE);
    }

    public Object unmarshal(Element element, BeanHandler beanHandler) throws Exception {
        String globalName = element.getLocalName();
        Unmarshaller<Element> unmarshaller = globalName2Unmarshaller.get(globalName);

        return unmarshaller.unmarshal(element, beanHandler);
    }

    public static JaxbeanUnmarshaller newInstance(Class<?>... types) throws Exception {
        Builder builder = new Builder();
        for (Class<?> type : types) {
            builder.addGlobalType(type);
        }
        builder.init();

        return new JaxbeanUnmarshaller(builder.globalName2Unmarshaller);
    }

    private static class Builder implements ElementUnmarshallerProvider {

        private Map<String, Unmarshaller<Element>> globalName2Unmarshaller = new HashMap<String, Unmarshaller<Element>>();
        private Map<Class<?>, String> globalType2Name = new HashMap<Class<?>, String>();
        private Map<Class<?>, InitializableElementUnmarshaller> type2Unmarshaller = new HashMap<Class<?>, InitializableElementUnmarshaller>();
        private Map<Class<?>, InitializableElementUnmarshaller> type2InitializedUnmarshaller = new HashMap<Class<?>, InitializableElementUnmarshaller>();

        public void init() throws Exception {
            while (!type2Unmarshaller.isEmpty()) {
                Collection<InitializableElementUnmarshaller> toBeInitialized = new ArrayList(
                        type2Unmarshaller.values());
                type2InitializedUnmarshaller.putAll(type2Unmarshaller);
                type2Unmarshaller.clear();

                for (InitializableElementUnmarshaller unmarshaller : toBeInitialized) {
                    unmarshaller.init(this);
                }
            }
        }

        public void addGlobalType(Class<?> type) throws Exception {
            String elementName = resolveRootElementName(type);
            Unmarshaller<Element> unmarshaller = getUnmarshallerForType(type);

            globalName2Unmarshaller.put(elementName, unmarshaller);
            globalType2Name.put(type, elementName);
        }

        @Override
        public Unmarshaller<Element> getUnmarshallerForType(Class<?> type) throws Exception {
            if (type2InitializedUnmarshaller.containsKey(type)) {
                return type2InitializedUnmarshaller.get(type);
            }
            if (type2Unmarshaller.containsKey(type)) {
                return type2Unmarshaller.get(type);
            }
            if (type == String.class) {
                return ElementTextContentUnmarshaller.INSTANCE;
            }

            InitializableElementUnmarshaller unmarshaller = createBeanUnmarshaller(type);
            type2Unmarshaller.put(type, unmarshaller);

            return unmarshaller;
        }

        protected InitializableElementUnmarshaller createBeanUnmarshaller(Class<?> type) throws Exception {
            return new BeanUnmarshaller(type);
        }

        @Override
        public void forGlobalUnmarshallerCompatibleWith(Class<?> type, Handler handler) {
            for (Entry<Class<?>, String> entry : globalType2Name.entrySet()) {
                Class<?> globalType = entry.getKey();
                String globalName = entry.getValue();

                if (!type.isAssignableFrom(globalType)) {
                    continue;
                }
                Unmarshaller<Element> unmarshaller = globalName2Unmarshaller.get(globalName);
                handler.handle(globalName, unmarshaller);
            }
        }

        private String resolveRootElementName(Class<?> type) {
            XmlRootElement xmlRootElement = type.getAnnotation(XmlRootElement.class);
            String name = xmlRootElement.name();
            if (name.equals(BeanUnmarshaller.AUTO_GENERATED_NAME)) {
                name = Introspector.decapitalize(type.getSimpleName());
            }
            return name;
        }
    }

    private enum ObjectBeanHandler implements BeanHandler<BeanWrapper> {

        INSTANCE;

        @Override
        public BeanWrapper createBean(Class<?> beanClass) throws Exception {
            Object instance = beanClass.newInstance();

            return PropertyAccessorFactory.forBeanPropertyAccess(instance);
        }

        @Override
        public void setBeanProperty(BeanWrapper bean, String propertyName, Object propertyValue) {
            bean.setPropertyValue(propertyName, propertyValue);
        }

        @Override
        public Object unmarshalWith(XmlAdapter xmlAdapter, Object from) throws Exception {
            return xmlAdapter.unmarshal(from);
        }

        @Override
        public Object postProcessList(List<Object> unprocessedList) {
            return unprocessedList;
        }

        @Override
        public Object postProcess(BeanWrapper bean) {
            return bean.getWrappedInstance();
        }
    }
}