alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Apache CXF example source code file (JAXBContextInitializer.java)

This example Apache CXF source code file (JAXBContextInitializer.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Apache CXF tags/keywords

annotation, annotation, class, class, genericarraytype, genericarraytype, jaxbcontextinitializer, object, parameterizedtype, reflection, throwable, type, type, typevariable, util, xmlaccesstype

The Apache CXF JAXBContextInitializer.java source code

/**
 * 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.cxf.jaxb;

import java.lang.annotation.Annotation;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Collection;
import java.util.Set;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlAdapter;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
import javax.xml.namespace.QName;

import org.apache.cxf.common.classloader.ClassLoaderUtils;
import org.apache.cxf.common.util.StringUtils;
import org.apache.cxf.service.ServiceModelVisitor;
import org.apache.cxf.service.model.MessageInfo;
import org.apache.cxf.service.model.MessagePartInfo;
import org.apache.cxf.service.model.OperationInfo;
import org.apache.cxf.service.model.ServiceInfo;
import org.apache.cxf.service.model.UnwrappedOperationInfo;

/**
 * Walks the service model and sets up the classes for the context.
 */
class JAXBContextInitializer extends ServiceModelVisitor {

    private Set<Class classes;
    private Collection<Object> typeReferences;

    public JAXBContextInitializer(ServiceInfo serviceInfo,
                                  Set<Class classes,
                                  Collection<Object> typeReferences) {
        super(serviceInfo);
        this.classes = classes;
        this.typeReferences = typeReferences;
    }

    @Override
    public void begin(MessagePartInfo part) {
        Class<?> clazz = part.getTypeClass();
        if (clazz == null) {
            return;
        }

        if (Exception.class.isAssignableFrom(clazz)) {
            //exceptions are handled special, make sure we mark it
            part.setProperty(JAXBDataBinding.class.getName() + ".CUSTOM_EXCEPTION",
                             Boolean.TRUE);
        }
        boolean isFromWrapper = part.getMessageInfo().getOperation().isUnwrapped();
        if (isFromWrapper 
            && !Boolean.TRUE.equals(part.getProperty("messagepart.isheader"))) {
            UnwrappedOperationInfo uop = (UnwrappedOperationInfo)part.getMessageInfo().getOperation();
            OperationInfo op = uop.getWrappedOperation();
            MessageInfo inf = null;
            if (uop.getInput() == part.getMessageInfo()) {
                inf = op.getInput();
            } else if (uop.getOutput() == part.getMessageInfo()) {
                inf = op.getOutput();
            }
            if (inf != null
                && inf.getMessagePart(0).getTypeClass() != null) {
                //if the wrapper has a type class, we don't need to do anything
                //as everything would have been discovered when walking the
                //wrapper type (unless it's a header which wouldn't be in the wrapper)
                return;
            }
        }
        if (isFromWrapper
            && clazz.isArray()
            && !Byte.TYPE.equals(clazz.getComponentType())) {
            clazz = clazz.getComponentType();
        }
        
        Annotation[] a = (Annotation[])part.getProperty("parameter.annotations");
        checkForAdapter(clazz, a);

        Type genericType = (Type) part.getProperty("generic.type");
        if (genericType != null) {
            boolean isList = Collection.class.isAssignableFrom(clazz);
            if (isFromWrapper) {
                if (genericType instanceof Class
                    && ((Class)genericType).isArray()) {
                    Class cl2 = (Class)genericType;
                    if (cl2.isArray()
                        && !Byte.TYPE.equals(cl2.getComponentType())) {
                        genericType = cl2.getComponentType();
                    }
                    addType(genericType);
                } else if (!isList) {
                    addType(genericType);
                }
            } else {
                addType(genericType, true);
            }

            if (isList
                && genericType instanceof ParameterizedType) {
                ParameterizedType pt = (ParameterizedType) genericType;
                if (pt.getActualTypeArguments().length > 0
                    && pt.getActualTypeArguments()[0] instanceof Class) {

                    Class<? extends Object> arrayCls =
                        Array.newInstance((Class) pt.getActualTypeArguments()[0], 0).getClass();
                    clazz = arrayCls;
                    part.setTypeClass(clazz);
                    if (isFromWrapper) {
                        addType(clazz.getComponentType(), true);
                    }
                } else if (pt.getActualTypeArguments().length > 0
                    && pt.getActualTypeArguments()[0] instanceof GenericArrayType) {
                    GenericArrayType gat = (GenericArrayType)pt.getActualTypeArguments()[0];
                    gat.getGenericComponentType();
                    Class<? extends Object> arrayCls =
                        Array.newInstance((Class) gat.getGenericComponentType(), 0).getClass();
                    clazz = Array.newInstance(arrayCls, 0).getClass();
                    part.setTypeClass(clazz);
                    if (isFromWrapper) {
                        addType(clazz.getComponentType(), true);
                    }
                }
            }
            if (isFromWrapper && isList) {
                clazz = null;
            }
        }
        if (clazz != null) {
            if (!isFromWrapper 
                && clazz.getAnnotation(XmlRootElement.class) == null
                && clazz.getAnnotation(XmlType.class) != null
                && StringUtils.isEmpty(clazz.getAnnotation(XmlType.class).name())) {
                createTypeReference(part.getName(), clazz);
            }
            
            addClass(clazz);
        }
    }
    
    private void createTypeReference(QName n, Class<?> cls) {
        Class<?> refClass = null;
        try {
            refClass = ClassLoaderUtils.loadClass("com.sun.xml.bind.api.TypeReference", this.getClass());
        } catch (Throwable ex) {
            try {
                refClass = ClassLoaderUtils.loadClass("com.sun.xml.internal.bind.api.TypeReference",
                                                      this.getClass());
            } catch (Throwable ex2) {
                //ignore
            }
        }
        if (refClass != null) {
            try {
                Object o =  refClass.getConstructor(QName.class, Type.class, new Annotation[0].getClass())
                    .newInstance(n, cls, new Annotation[0]);
                typeReferences.add(o);
            } catch (Throwable e) {
                //ignore
            }
        }
    }

    private void checkForAdapter(Class<?> clazz, Annotation[] anns) {
        if (anns != null) {
            for (Annotation a : anns) {
                if (XmlJavaTypeAdapter.class.isAssignableFrom(a.annotationType())) {
                    inspectTypeAdapter(((XmlJavaTypeAdapter)a).value());
                }
            }
        }
        XmlJavaTypeAdapter xjta = clazz.getAnnotation(XmlJavaTypeAdapter.class);
        if (xjta != null) {
            inspectTypeAdapter(xjta.value());
        }
        
    }

    private void addType(Type cls) {
        addType(cls, false);
    }
    private void addType(Type cls, boolean allowArray) {
        if (cls instanceof Class) {
            if (((Class)cls).isArray() && !allowArray) {
                addClass(((Class)cls).getComponentType());
            } else {
                addClass((Class)cls);
            }
        } else if (cls instanceof ParameterizedType) {
            addType(((ParameterizedType)cls).getRawType());
            for (Type t2 : ((ParameterizedType)cls).getActualTypeArguments()) {
                addType(t2);
            }
        } else if (cls instanceof GenericArrayType) {
            Class ct;
            GenericArrayType gt = (GenericArrayType)cls;
            Type componentType = gt.getGenericComponentType();
            if (componentType instanceof Class) {
                ct = (Class)componentType;
            } else {
                TypeVariable tv = (TypeVariable)componentType;
                Type[] bounds = tv.getBounds();
                if (bounds != null && bounds.length == 1) {
                    if (bounds[0] instanceof Class) {
                        ct = (Class)bounds[0];
                    } else {
                        throw new IllegalArgumentException("Unable to determine type for: " + tv);
                    }
                } else {
                    throw new IllegalArgumentException("Unable to determine type for: " + tv);
                }
            }
            ct = Array.newInstance(ct, 0).getClass();

            addClass(ct);
        } else if (cls instanceof WildcardType) {
            for (Type t : ((WildcardType)cls).getUpperBounds()) {
                addType(t);
            }
            for (Type t : ((WildcardType)cls).getLowerBounds()) {
                addType(t);
            }
        } else if (cls instanceof TypeVariable) {
            for (Type t : ((TypeVariable)cls).getBounds()) {
                addType(t);
            }
        }
    }


    private  void addClass(Class<?> cls) {
        if (Throwable.class.isAssignableFrom(cls)) {
            if (!Throwable.class.equals(cls)
                && !Exception.class.equals(cls)) {
                walkReferences(cls);
            }
            addClass(String.class);
        } else {
            cls = JAXBUtils.getValidClass(cls);
            if (null != cls) {
                if (cls.getSuperclass() != null) {
                    //JAXB should do this, but it doesn't always.
                    //in particular, older versions of jaxb don't
                    addClass(cls.getSuperclass());
                }
                
                if (cls.isInterface()) {
                    //interfaces cannot be added directly, however, they
                    //may have some interesting annoations we should consider
                    XmlSeeAlso xsa = cls.getAnnotation(XmlSeeAlso.class);
                    if (xsa != null) {
                        for (Class c : xsa.value()) {
                            addClass(c);
                        }
                    }
                    XmlJavaTypeAdapter xjta = cls.getAnnotation(XmlJavaTypeAdapter.class);
                    if (xjta != null) {
                        Class<? extends XmlAdapter> c2 = xjta.value();
                        inspectTypeAdapter(c2);
                    }
                } else if (classes.contains(cls)) {
                    return;
                } else {
                    classes.add(cls);
                    walkReferences(cls);
                }
            }
        }
    }

    private void inspectTypeAdapter(Class<? extends XmlAdapter> aclass) {
        Class<?> c2 = aclass;
        Type sp = c2.getGenericSuperclass();
        while (!XmlAdapter.class.equals(c2) && c2 != null) {
            sp = c2.getGenericSuperclass();
            c2 = c2.getSuperclass();
        }
        if (sp instanceof ParameterizedType) {
            addType(((ParameterizedType)sp).getActualTypeArguments()[0]);
        }
    }

    private void walkReferences(Class<?> cls) {
        if (cls == null) {
            return;
        }
        if (cls.getName().startsWith("java.")
            || cls.getName().startsWith("javax.")) {
            return;
        }
        //walk the public fields/methods to try and find all the classes. JAXB will only load the
        //EXACT classes in the fields/methods if they are in a different package. Thus,
        //subclasses won't be found and the xsi:type stuff won't work at all.
        //We'll grab the public field/method types and then add the ObjectFactory stuff
        //as well as look for jaxb.index files in those packages.

        XmlAccessorType accessorType = cls.getAnnotation(XmlAccessorType.class);
        if (accessorType == null && cls.getPackage() != null) {
            accessorType = cls.getPackage().getAnnotation(XmlAccessorType.class);
        }
        XmlAccessType accessType = accessorType != null ? accessorType.value() : XmlAccessType.PUBLIC_MEMBER;

        if (accessType != XmlAccessType.PROPERTY) {   // only look for fields if we are instructed to
            //fields are accessible even if not public, must look at the declared fields
            //then walk to parents declared fields, etc...
            Field fields[] = cls.getDeclaredFields(); 
            for (Field f : fields) {
                if (isFieldAccepted(f, accessType)) {
                    addType(f.getGenericType());
                }
            }
            walkReferences(cls.getSuperclass());
        }

        if (accessType != XmlAccessType.FIELD) {   // only look for methods if we are instructed to
            Method methods[] = cls.getDeclaredMethods(); 
            for (Method m : methods) {
                if (isMethodAccepted(m, accessType)) {
                    addType(m.getGenericReturnType());
                    for (Type t : m.getGenericParameterTypes()) {
                        addType(t);
                    }
                }
            }
        }
    }

    /**
     * Checks if the field is accepted as a JAXB property.
     */
    static boolean isFieldAccepted(Field field, XmlAccessType accessType) {
        // We only accept non static fields which are not marked @XmlTransient
        if (Modifier.isStatic(field.getModifiers()) || field.isAnnotationPresent(XmlTransient.class)) {
            return false;
        }
        if (accessType == XmlAccessType.PUBLIC_MEMBER 
            && !Modifier.isPublic(field.getModifiers())) {
            return false;
        }
        if (field.getAnnotation(XmlJavaTypeAdapter.class) != null) {
            return false;
        }
        if (accessType == XmlAccessType.NONE
            || accessType == XmlAccessType.PROPERTY) {
            return checkJaxbAnnotation(field.getAnnotations());
        } else {
            return true;
        }
    }

    /**
     * Checks if the method is accepted as a JAXB property getter.
     */
    static boolean isMethodAccepted(Method method, XmlAccessType accessType) {
        // We only accept non static property getters which are not marked @XmlTransient
        if (Modifier.isStatic(method.getModifiers()) 
            || method.isAnnotationPresent(XmlTransient.class)
            || !Modifier.isPublic(method.getModifiers())) {
            return false;
        }

        // must not have parameters and return type must not be void
        if (method.getReturnType() == Void.class 
            || method.getParameterTypes().length != 0
            || method.getDeclaringClass().equals(Throwable.class)) {
            return false;
        }

        boolean isPropGetter = method.getName().startsWith("get") || method.getName().startsWith("is");

        if (!isPropGetter 
            || method.getAnnotation(XmlJavaTypeAdapter.class) != null) {
            return false;
        }
        int beginIndex = 3;
        if (method.getName().startsWith("is")) {
            beginIndex = 2;
        }
        try {
            method.getDeclaringClass().getMethod("set" + method.getName().substring(beginIndex),
                                                 new Class[] {method.getReturnType()});
        } catch (Exception e) {
            //getter, but no setter
            return false;
        }

        if (accessType == XmlAccessType.NONE
            || accessType == XmlAccessType.FIELD) {
            return checkJaxbAnnotation(method.getAnnotations());
        } else {
            return true;
        }
    }

    /**
     * Checks if there are JAXB annotations among the annotations of the class member.
     * @param annotations the array of annotations from the class member
     * @return true if JAXB annotations are present, false otherwise
     */
    private static boolean checkJaxbAnnotation(Annotation[] annotations) {
        // must check if there are any jaxb annotations
        Package jaxbAnnotationsPackage = XmlElement.class.getPackage();
        for (Annotation annotation : annotations) {
            if (annotation.annotationType().getPackage() == jaxbAnnotationsPackage) {
                return true;
            }
        }
        return false;
    }
}

Other Apache CXF examples (source code examples)

Here is a short list of links related to this Apache CXF JAXBContextInitializer.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.