Package org.apache.tuscany.sca.databinding.jaxb

Source Code of org.apache.tuscany.sca.databinding.jaxb.BeanXMLStreamReaderImpl$Accessor

/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements.  See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership.  The ASF licenses this file
* to you 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 org.apache.tuscany.sca.databinding.jaxb;

import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.namespace.QName;

import org.apache.tuscany.sca.databinding.impl.SimpleTypeMapperImpl;
import org.apache.tuscany.sca.databinding.xml.SimpleXmlNodeImpl;
import org.apache.tuscany.sca.databinding.xml.XmlNode;
import org.apache.tuscany.sca.databinding.xml.XmlTreeStreamReaderImpl;
import org.apache.tuscany.sca.interfacedef.util.TypeInfo;

import com.sun.xml.bind.v2.model.annotation.RuntimeInlineAnnotationReader;
import com.sun.xml.bind.v2.model.core.Ref;
import com.sun.xml.bind.v2.model.impl.RuntimeModelBuilder;
import com.sun.xml.bind.v2.model.runtime.RuntimeClassInfo;
import com.sun.xml.bind.v2.model.runtime.RuntimePropertyInfo;
import com.sun.xml.bind.v2.model.runtime.RuntimeTypeInfoSet;
import com.sun.xml.bind.v2.runtime.IllegalAnnotationsException;
import com.sun.xml.bind.v2.runtime.JAXBContextImpl;

/**
* @version $Rev: 601501 $ $Date: 2007-12-05 20:23:21 +0000 (Wed, 05 Dec 2007) $
*/
public class BeanXMLStreamReaderImpl extends XmlTreeStreamReaderImpl {
    private final static Comparator<Accessor> COMPARATOR = new Comparator<Accessor>() {
        public int compare(Accessor o1, Accessor o2) {
            return o1.getName().compareTo(o2.getName());
        }
    };

    private final static String XSI_PREFIX = "xsi";
    private final static String XSI_NS = "http://www.w3.org/2001/XMLSchema-instance";

    private final static XmlNode getXSIType(QName realType) {
        QName xsiType = new QName(XSI_NS, "type", XSI_PREFIX);
        String prefix = realType.getPrefix();
        String typeName = realType.getLocalPart();
        if (prefix != null && !prefix.equals("")) {
            typeName = prefix + ":" + realType.getLocalPart();
        }
        return new SimpleXmlNodeImpl(xsiType, XmlNode.Type.ATTRIBUTE);
    }

    /**
     * Represent a Map.Entry XML node
     * @version $Rev: 601501 $ $Date: 2007-12-05 20:23:21 +0000 (Wed, 05 Dec 2007) $
     */
    public static class MapEntryXmlNodeImpl extends SimpleXmlNodeImpl implements XmlNode {
        private Map.Entry entry;

        public MapEntryXmlNodeImpl(Entry entry) {
            super(new QName("", "entry"), entry);
            this.entry = entry;
        }

        public Iterator<XmlNode> children() {
            List<XmlNode> nodes = new ArrayList<XmlNode>();
            XmlNode key = new BeanXmlNodeImpl(new QName("", "key"), entry.getKey());
            XmlNode value = new BeanXmlNodeImpl(new QName("", "value"), entry.getValue());
            nodes.add(key);
            nodes.add(value);
            return nodes.iterator();
        }
    }

    public static class BeanXmlNodeImpl extends SimpleXmlNodeImpl implements XmlNode {
        private static final Object[] NULL = null;
        private static final SimpleTypeMapperImpl MAPPER = new SimpleTypeMapperImpl();

        public BeanXmlNodeImpl(Object bean) {
            super(getName(bean == null ? null : bean.getClass()), bean);
        }

        public BeanXmlNodeImpl(QName name, Object bean) {
            super(name, bean);
        }

        private static boolean isSimpleType(Class<?> javaType) {
            return SimpleTypeMapperImpl.getXMLType(javaType) != null;
        }

        private static String getStringValue(Object o) {
            if (o == null) {
                return null;
            }
            TypeInfo info = SimpleTypeMapperImpl.getXMLType(o.getClass());
            if (info != null) {
                return MAPPER.toXMLLiteral(info.getQName(), o, null);
            } else {
                return String.valueOf(o);
            }
        }

        public Iterator<XmlNode> children() {
            if (name == null) {
                return null;
            }
            if (value == null) {
                return super.children();
            }
            if (isSimpleType(value.getClass())) {
                XmlNode textNode = new BeanXmlNodeImpl(null, value);
                return Arrays.asList(textNode).iterator();
            }
            if (Map.class.isAssignableFrom(value.getClass())) {
                List<XmlNode> entries = new ArrayList<XmlNode>();
                Map map = (Map)value;
                if (map != null) {
                    for (Object e : map.entrySet()) {
                        Map.Entry entry = (Map.Entry)e;
                        entries.add(new MapEntryXmlNodeImpl(entry));
                    }
                }
                return entries.iterator();
            }
            try {
                Map<String, Accessor> accessorMap = getAccessors(value);
                List<Accessor> accessorList = new ArrayList<Accessor>(accessorMap.values());
                Collections.sort(accessorList, COMPARATOR);

                List<XmlNode> props = new ArrayList<XmlNode>();
                for (Accessor accessor : accessorList) {
                    Class<?> pType = accessor.getType();

                    QName pName = new QName(name.getNamespaceURI(), accessor.getName());
                    Object pValue = accessor.getValue();
                    if (pType.isArray()) {
                        if (pValue != null) {
                            int i1 = Array.getLength(pValue);
                            for (int j = 0; j < i1; j++) {
                                Object o = Array.get(pValue, j);
                                props.add(new BeanXmlNodeImpl(pName, o));
                            }
                        } else {
                            // TODO: How to handle null?
                        }
                    } else if (Collection.class.isAssignableFrom(pType)) {
                        Collection objList = (Collection)pValue;
                        if (objList != null && objList.size() > 0) {
                            for (Iterator j = objList.iterator(); j.hasNext();) {
                                Object o = j.next();
                                props.add(new BeanXmlNodeImpl(pName, o));
                            }

                        } else {
                            // How to handle null
                        }
                    } else {
                        props.add(new BeanXmlNodeImpl(pName, pValue));
                    }
                }
                return props.iterator();
            } catch (Exception e) {
                throw new IllegalArgumentException(e);
            }
        }

        public QName getName() {
            return name;
        }

        public String getValue() {
            return getStringValue(value);
        }

        public static QName getName(Class<?> cls) {
            if (cls == null) {
                return null;
            }
            Package pkg = cls.getPackage();
            if (pkg == null) {
                return new QName("", cls.getSimpleName());
            }
            StringBuffer ns = new StringBuffer("http://");
            String[] names = pkg.getName().split("\\.");
            for (int i = names.length - 1; i >= 0; i--) {
                ns.append(names[i]);
                if (i != 0) {
                    ns.append('.');
                }
            }
            ns.append('/');
            return new QName(ns.toString(), cls.getSimpleName());
        }

    }

    public BeanXMLStreamReaderImpl(QName name, Object bean) {
        super(getXmlNode(name, bean));
    }

    private static BeanXmlNodeImpl getXmlNode(QName name, Object bean) {
        BeanXmlNodeImpl root = null;
        if (name != null) {
            root = new BeanXmlNodeImpl(name, bean);
        } else {
            root = new BeanXmlNodeImpl(bean);
        }
        return root;
    }

    public static interface Accessor {
        String getName();

        Class<?> getType();

        Object getValue() throws Exception;

        void setValue(Object value) throws Exception;
    }

    private static RuntimeTypeInfoSet create(Class... classes) throws Exception {
        IllegalAnnotationsException.Builder errorListener = new IllegalAnnotationsException.Builder();
        RuntimeInlineAnnotationReader reader = new RuntimeInlineAnnotationReader();
        JAXBContextImpl context =
            new JAXBContextImpl(classes, null, Collections.<Class, Class> emptyMap(), null, false, reader, false, false);
        RuntimeModelBuilder builder =
            new RuntimeModelBuilder(context, reader, Collections.<Class, Class> emptyMap(), null);
        builder.setErrorHandler(errorListener);
        for (Class c : classes)
            builder.getTypeInfo(new Ref<Type, Class>(c));

        RuntimeTypeInfoSet r = builder.link();
        errorListener.check();
        return r;
    }

    private static class JAXBAccessor implements Accessor {
        private Object target;
        private RuntimePropertyInfo prop;

        public JAXBAccessor(Object target, RuntimePropertyInfo field) {
            super();
            this.target = target;
            this.prop = field;
        }

        public String getName() {
            return prop.getName();
        }

        public Object getValue() throws Exception {
            return prop.getAccessor().get(target);
        }

        public void setValue(Object value) throws Exception {
            prop.getAccessor().set(target, value);
        }

        public Class<?> getType() {
            Type type = prop.getRawType();
            if (type instanceof Class) {
                return (Class<?>)type;
            } else if (type instanceof ParameterizedType) {
                ParameterizedType pType = (ParameterizedType)type;
                type = pType.getRawType();
                if (type instanceof Class) {
                    return (Class<?>)type;
                }
            }
            return Object.class;
        }

    }

    private static Map<String, Accessor> getAccessors(Object target) throws Exception {
        if (target == null) {
            return Collections.emptyMap();
        }
        Map<String, Accessor> map = new HashMap<String, Accessor>();
        Class<?> type = target.getClass();
        RuntimeTypeInfoSet set = create(type);
        RuntimeClassInfo clsInfo = (RuntimeClassInfo)set.getTypeInfo(type);
        for (RuntimePropertyInfo f : clsInfo.getProperties()) {
            map.put(f.getName(), new JAXBAccessor(target, f));
        }
        return map;
    }

}
TOP

Related Classes of org.apache.tuscany.sca.databinding.jaxb.BeanXMLStreamReaderImpl$Accessor

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.