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

Java example source code file (TypeUtil.java)

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

Learn more about this Java project at its project page.

Java - Java tags/keywords

classnotfoundexception, comparator, errorreceiver, jclass, jcodemodel, jdefinedclass, jtype, list, locator, sax, saxparseexception, set, string, treeset, typeutil, util

The TypeUtil.java Java example source code

/*
 * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * This code is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License version 2 only, as
 * published by the Free Software Foundation.  Oracle designates this
 * particular file as subject to the "Classpath" exception as provided
 * by Oracle in the LICENSE file that accompanied this code.
 *
 * This code is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * version 2 for more details (a copy is included in the LICENSE file that
 * accompanied this code).
 *
 * You should have received a copy of the GNU General Public License version
 * 2 along with this work; if not, write to the Free Software Foundation,
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 *
 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 * or visit www.oracle.com if you need additional information or have any
 * questions.
 */

package com.sun.tools.internal.xjc.reader;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

import com.sun.codemodel.internal.JClass;
import com.sun.codemodel.internal.JCodeModel;
import com.sun.codemodel.internal.JDefinedClass;
import com.sun.codemodel.internal.JType;
import com.sun.tools.internal.xjc.ErrorReceiver;

import org.xml.sax.Locator;
import org.xml.sax.SAXParseException;

/**
 * Type-related utility methods.
 *
 * @author
 *    <a href="mailto:kohsuke.kawaguchi@sun.com">Kohsuke KAWAGUCHI
 */
public class TypeUtil {


    /**
     * Computes the common base type of two types.
     *
     * @param types
     *      set of {@link JType} objects.
     */
    public static JType getCommonBaseType( JCodeModel codeModel, Collection<? extends JType> types ) {
        return getCommonBaseType( codeModel, types.toArray(new JType[types.size()]) );
    }

    /**
     * Computes the common base type of types.
     *
     * TODO: this is a very interesting problem. Since one type has possibly
     * multiple base types, it's not an easy problem.
     * The current implementation is very naive.
     *
     * To make the result deterministic across differente JVMs, we have to
     * use a Set whose ordering is deterministic.
     */
    public static JType getCommonBaseType(JCodeModel codeModel, JType... t) {
        // first, eliminate duplicates.
        Set<JType> uniqueTypes = new TreeSet(typeComparator);
        for (JType type : t)
            uniqueTypes.add(type);

        // if this yields only one type. return now.
        // this is the only case where we can return a primitive type
        // from this method
        if (uniqueTypes.size() == 1)
            return uniqueTypes.iterator().next();

        // assertion failed. nullType can be used only under a very special circumstance
        assert !uniqueTypes.isEmpty();

        // the null type doesn't need to be taken into account.
        uniqueTypes.remove(codeModel.NULL);

        // box all the types and compute the intersection of all types
        Set<JClass> s = null;

        for (JType type : uniqueTypes) {
            JClass cls = type.boxify();

            if (s == null)
                s = getAssignableTypes(cls);
            else
                s.retainAll(getAssignableTypes(cls));
        }

        // any JClass can be casted to Object, so make sure it's always there
        s.add( codeModel.ref(Object.class));

        // refine 's' by removing "lower" types.
        // for example, if we have both java.lang.Object and
        // java.io.InputStream, then we don't want to use java.lang.Object.

        JClass[] raw = s.toArray(new JClass[s.size()]);
        s.clear();

        for (int i = 0; i < raw.length; i++) { // for each raw[i]
            int j;
            for (j = 0; j < raw.length; j++) { // see if raw[j] "includes" raw[i]
                if (i == j)
                    continue;

                if (raw[i].isAssignableFrom(raw[j]))
                    break; // raw[j] is derived from raw[i], hence j includes i.
            }

            if (j == raw.length)
                // no other type inclueds raw[i]. remember this value.
                s.add(raw[i]);
        }

        assert !s.isEmpty(); // since at least java.lang.Object has to be there

        // we now pick the candidate for the return type
        JClass result = pickOne(s);

        // finally, sometimes this method is used to compute the base type of types like
        // JAXBElement<A>, JAXBElement, and JAXBElement.
        // for those inputs, at this point result=JAXBElement.
        //
        // here, we'll try to figure out the parameterization
        // so that we can return JAXBElement<? extends D> instead of just "JAXBElement".
        if(result.isParameterized())
            return result;

        // for each uniqueType we store the list of base type parameterization
        List<List parameters = new ArrayList>(uniqueTypes.size());
        int paramLen = -1;

        for (JType type : uniqueTypes) {
            JClass cls = type.boxify();
            JClass bp = cls.getBaseClass(result);
            // if there's no parameterization in the base type,
            // we won't do any better than <?>. Thus no point in trying to figure out the parameterization.
            // just return the base type.
            if(bp.equals(result))
                return result;

            assert bp.isParameterized();
            List<JClass> tp = bp.getTypeParameters();
            parameters.add(tp);

            assert paramLen==-1 || paramLen==tp.size();
                // since 'bp' always is a parameterized version of 'result', it should always
                // have the same number of parameters.
            paramLen = tp.size();
        }

        List<JClass> paramResult = new ArrayList();
        List<JClass> argList = new ArrayList(parameters.size());
        // for each type parameter compute the common base type
        for( int i=0; i<paramLen; i++ ) {
            argList.clear();
            for (List<JClass> list : parameters)
                argList.add(list.get(i));

            // compute the lower bound.
            JClass bound = (JClass)getCommonBaseType(codeModel,argList);
            boolean allSame = true;
            for (JClass a : argList)
                allSame &= a.equals(bound);
            if(!allSame)
                bound = bound.wildcard();

            paramResult.add(bound);
        }

        return result.narrow(paramResult);
    }

    private static JClass pickOne(Set<JClass> s) {
        // we may have more than one candidates at this point.
        // any user-defined generated types should have
        // precedence over system-defined existing types.
        //
        // so try to return such a type if any.
        for (JClass c : s)
            if (c instanceof JDefinedClass)
                return c;

        // we can do more if we like. for example,
        // we can avoid types in the RI runtime.
        // but for now, just return the first one.
        return s.iterator().next();
    }

    private static Set<JClass> getAssignableTypes( JClass t ) {
        Set<JClass> r = new TreeSet(typeComparator);
        getAssignableTypes(t,r);
        return r;
    }

    /**
     * Returns the set of all classes/interfaces that a given type
     * implements/extends, including itself.
     *
     * For example, if you pass java.io.FilterInputStream, then the returned
     * set will contain java.lang.Object, java.lang.InputStream, and
     * java.lang.FilterInputStream.
     */
    private static void getAssignableTypes( JClass t, Set<JClass> s ) {
        if(!s.add(t))
            return;

        // add its raw type
        s.add(t.erasure());

        // if this type is added for the first time,
        // recursively process the super class.
        JClass _super = t._extends();
        if(_super!=null)
            getAssignableTypes(_super,s);

        // recursively process all implemented interfaces
        Iterator<JClass> itr = t._implements();
        while(itr.hasNext())
            getAssignableTypes(itr.next(),s);
    }

    /**
     * Obtains a {@link JType} object for the string representation
     * of a type.
     */
    public static JType getType( JCodeModel codeModel,
        String typeName, ErrorReceiver errorHandler, Locator errorSource ) {

        try {
            return codeModel.parseType(typeName);
        } catch( ClassNotFoundException ee ) {

            // make it a warning
            errorHandler.warning( new SAXParseException(
                Messages.ERR_CLASS_NOT_FOUND.format(typeName)
                ,errorSource));

            // recover by assuming that it's a class that derives from Object
            return codeModel.directClass(typeName);
        }
    }

    /**
     * Compares {@link JType} objects by their names.
     */
    private static final Comparator<JType> typeComparator = new Comparator() {
        public int compare(JType t1, JType t2) {
            return t1.fullName().compareTo(t2.fullName());
        }
    };
}

Other Java examples (source code examples)

Here is a short list of links related to this Java TypeUtil.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.