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

Java example source code file (TypedAnnotationWriter.java)

This example Java source code file (TypedAnnotationWriter.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

annotation, class, illegalargumentexception, integer, jannotationuse, jannotationwriter, jtype, method, object, parameterizedtype, reflection, string, suppresswarnings, typedannotationwriter, util

The TypedAnnotationWriter.java Java example source code

/*
 * Copyright (c) 1997, 2010, 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.codemodel.internal;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.Type;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.InvocationTargetException;
import java.lang.annotation.Annotation;
import java.util.Map;
import java.util.HashMap;

/**
 * Dynamically implements the typed annotation writer interfaces.
 *
 * @author Kohsuke Kawaguchi
 */
class TypedAnnotationWriter<A extends Annotation,W extends JAnnotationWriter
    implements InvocationHandler, JAnnotationWriter<A> {
    /**
     * This is what we are writing to.
     */
    private final JAnnotationUse use;

    /**
     * The annotation that we are writing.
     */
    private final Class<A> annotation;

    /**
     * The type of the writer.
     */
    private final Class<W> writerType;

    /**
     * Keeps track of writers for array members.
     * Lazily created.
     */
    private Map<String,JAnnotationArrayMember> arrays;

    public TypedAnnotationWriter(Class<A> annotation, Class writer, JAnnotationUse use) {
        this.annotation = annotation;
        this.writerType = writer;
        this.use = use;
    }

    public JAnnotationUse getAnnotationUse() {
        return use;
    }

    public Class<A> getAnnotationType() {
        return annotation;
    }

    @SuppressWarnings("unchecked")
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        if(method.getDeclaringClass()==JAnnotationWriter.class) {
            try {
                return method.invoke(this,args);
            } catch (InvocationTargetException e) {
                throw e.getTargetException();
            }
        }

        String name = method.getName();
        Object arg=null;
        if(args!=null && args.length>0)
            arg = args[0];

        // check how it's defined on the annotation
        Method m = annotation.getDeclaredMethod(name);
        Class<?> rt = m.getReturnType();

        // array value
        if(rt.isArray()) {
            return addArrayValue(proxy,name,rt.getComponentType(),method.getReturnType(),arg);
        }

        // sub annotation
        if(Annotation.class.isAssignableFrom(rt)) {
            Class<? extends Annotation> r = (Class)rt;
            return new TypedAnnotationWriter(
                r,method.getReturnType(),use.annotationParam(name,r)).createProxy();
        }

        // scalar value

        if(arg instanceof JType) {
            JType targ = (JType) arg;
            checkType(Class.class,rt);
            if(m.getDefaultValue()!=null) {
                // check the default
                if(targ.equals(targ.owner().ref((Class)m.getDefaultValue())))
                    return proxy;   // defaulted
            }
            use.param(name,targ);
            return proxy;
        }

        // other Java built-in types
        checkType(arg.getClass(),rt);
        if(m.getDefaultValue()!=null && m.getDefaultValue().equals(arg))
            // defaulted. no need to write out.
            return proxy;

        if(arg instanceof String) {
            use.param(name,(String)arg);
            return proxy;
        }
        if(arg instanceof Boolean) {
            use.param(name,(Boolean)arg);
            return proxy;
        }
        if(arg instanceof Integer) {
            use.param(name,(Integer)arg);
            return proxy;
        }
        if(arg instanceof Class) {
            use.param(name,(Class)arg);
            return proxy;
        }
        if(arg instanceof Enum) {
            use.param(name,(Enum)arg);
            return proxy;
        }

        throw new IllegalArgumentException("Unable to handle this method call "+method.toString());
    }

    @SuppressWarnings("unchecked")
        private Object addArrayValue(Object proxy,String name, Class itemType, Class expectedReturnType, Object arg) {
        if(arrays==null)
            arrays = new HashMap<String,JAnnotationArrayMember>();
        JAnnotationArrayMember m = arrays.get(name);
        if(m==null) {
            m = use.paramArray(name);
            arrays.put(name,m);
        }

        // sub annotation
        if(Annotation.class.isAssignableFrom(itemType)) {
            Class<? extends Annotation> r = (Class)itemType;
            if(!JAnnotationWriter.class.isAssignableFrom(expectedReturnType))
                throw new IllegalArgumentException("Unexpected return type "+expectedReturnType);
            return new TypedAnnotationWriter(r,expectedReturnType,m.annotate(r)).createProxy();
        }

        // primitive
        if(arg instanceof JType) {
            checkType(Class.class,itemType);
            m.param((JType)arg);
            return proxy;
        }
        checkType(arg.getClass(),itemType);
        if(arg instanceof String) {
            m.param((String)arg);
            return proxy;
        }
        if(arg instanceof Boolean) {
            m.param((Boolean)arg);
            return proxy;
        }
        if(arg instanceof Integer) {
            m.param((Integer)arg);
            return proxy;
        }
        if(arg instanceof Class) {
            m.param((Class)arg);
            return proxy;
        }
        // TODO: enum constant. how should we handle it?

        throw new IllegalArgumentException("Unable to handle this method call ");
    }


    /**
     * Check if the type of the argument matches our expectation.
     * If not, report an error.
     */
    private void checkType(Class<?> actual, Class expected) {
        if(expected==actual || expected.isAssignableFrom(actual))
            return; // no problem

        if( expected==JCodeModel.boxToPrimitive.get(actual) )
            return; // no problem

        throw new IllegalArgumentException("Expected "+expected+" but found "+actual);
    }

    /**
     * Creates a proxy and returns it.
     */
    @SuppressWarnings("unchecked")
        private W createProxy() {
        return (W)Proxy.newProxyInstance(
            SecureLoader.getClassClassLoader(writerType),new Class[]{writerType},this);
    }

    /**
     * Creates a new typed annotation writer.
     */
    @SuppressWarnings("unchecked")
        static <W extends JAnnotationWriter W create(Class w, JAnnotatable annotatable) {
        Class<? extends Annotation> a = findAnnotationType(w);
        return (W)new TypedAnnotationWriter(a,w,annotatable.annotate(a)).createProxy();
    }

    private static Class<? extends Annotation> findAnnotationType(Class clazz) {
        for( Type t : clazz.getGenericInterfaces()) {
            if(t instanceof ParameterizedType) {
                ParameterizedType p = (ParameterizedType) t;
                if(p.getRawType()==JAnnotationWriter.class)
                    return (Class<? extends Annotation>)p.getActualTypeArguments()[0];
            }
            if(t instanceof Class<?>) {
                // recursive search
                Class<? extends Annotation> r = findAnnotationType((Class)t);
                if(r!=null)     return r;
            }
        }
        return null;
    }
}

Other Java examples (source code examples)

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