All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openjdk.tools.javac.model.AnnotationProxyMaker Maven / Gradle / Ivy

The newest version!
/*
 * Copyright (c) 2005, 2014, 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 org.openjdk.tools.javac.model;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.lang.annotation.*;
import java.lang.reflect.Array;
import java.lang.reflect.Method;
import java.util.LinkedHashMap;
import java.util.Map;
import sun.reflect.annotation.*;

import javax.lang.model.type.MirroredTypeException;
import javax.lang.model.type.MirroredTypesException;
import javax.lang.model.type.TypeMirror;

import org.openjdk.tools.javac.code.*;
import org.openjdk.tools.javac.code.Symbol.*;
import org.openjdk.tools.javac.code.Type.ArrayType;
import org.openjdk.tools.javac.util.*;

import static org.openjdk.tools.javac.code.Scope.LookupKind.NON_RECURSIVE;
import static org.openjdk.tools.javac.code.Kinds.Kind.*;

/**
 * A generator of dynamic proxy implementations of
 * java.lang.annotation.Annotation.
 *
 * 

The "dynamic proxy return form" of an annotation element value is * the form used by sun.reflect.annotation.AnnotationInvocationHandler. * *

This is NOT part of any supported API. * If you write code that depends on this, you do so at your own risk. * This code and its internal interfaces are subject to change or * deletion without notice. */ public class AnnotationProxyMaker { private final Attribute.Compound anno; private final Class annoType; private AnnotationProxyMaker(Attribute.Compound anno, Class annoType) { this.anno = anno; this.annoType = annoType; } /** * Returns a dynamic proxy for an annotation mirror. */ public static A generateAnnotation( Attribute.Compound anno, Class annoType) { AnnotationProxyMaker apm = new AnnotationProxyMaker(anno, annoType); return annoType.cast(apm.generateAnnotation()); } /** * Returns a dynamic proxy for an annotation mirror. */ private Annotation generateAnnotation() { return AnnotationParser.annotationForMap(annoType, getAllReflectedValues()); } /** * Returns a map from element names to their values in "dynamic * proxy return form". Includes all elements, whether explicit or * defaulted. */ private Map getAllReflectedValues() { Map res = new LinkedHashMap<>(); for (Map.Entry entry : getAllValues().entrySet()) { MethodSymbol meth = entry.getKey(); Object value = generateValue(meth, entry.getValue()); if (value != null) { res.put(meth.name.toString(), value); } else { // Ignore this element. May (properly) lead to // IncompleteAnnotationException somewhere down the line. } } return res; } /** * Returns a map from element symbols to their values. * Includes all elements, whether explicit or defaulted. */ private Map getAllValues() { Map res = new LinkedHashMap<>(); // First find the default values. ClassSymbol sym = (ClassSymbol) anno.type.tsym; for (Symbol s : sym.members().getSymbols(NON_RECURSIVE)) { if (s.kind == MTH) { MethodSymbol m = (MethodSymbol) s; Attribute def = m.getDefaultValue(); if (def != null) res.put(m, def); } } // Next find the explicit values, possibly overriding defaults. for (Pair p : anno.values) res.put(p.fst, p.snd); return res; } /** * Converts an element value to its "dynamic proxy return form". * Returns an exception proxy on some errors, but may return null if * a useful exception cannot or should not be generated at this point. */ private Object generateValue(MethodSymbol meth, Attribute attr) { ValueVisitor vv = new ValueVisitor(meth); return vv.getValue(attr); } private class ValueVisitor implements Attribute.Visitor { private MethodSymbol meth; // annotation element being visited private Class returnClass; // return type of annotation element private Object value; // value in "dynamic proxy return form" ValueVisitor(MethodSymbol meth) { this.meth = meth; } Object getValue(Attribute attr) { Method method; // runtime method of annotation element try { method = annoType.getMethod(meth.name.toString()); } catch (NoSuchMethodException e) { return null; } returnClass = method.getReturnType(); attr.accept(this); if (!(value instanceof ExceptionProxy) && !AnnotationType.invocationHandlerReturnType(returnClass) .isInstance(value)) { typeMismatch(method, attr); } return value; } public void visitConstant(Attribute.Constant c) { value = c.getValue(); } public void visitClass(Attribute.Class c) { value = new MirroredTypeExceptionProxy(c.classType); } public void visitArray(Attribute.Array a) { Name elemName = ((ArrayType) a.type).elemtype.tsym.getQualifiedName(); if (elemName.equals(elemName.table.names.java_lang_Class)) { // Class[] // Construct a proxy for a MirroredTypesException ListBuffer elems = new ListBuffer<>(); for (Attribute value : a.values) { Type elem = ((Attribute.Class) value).classType; elems.append(elem); } value = new MirroredTypesExceptionProxy(elems.toList()); } else { int len = a.values.length; Class returnClassSaved = returnClass; returnClass = returnClass.getComponentType(); try { Object res = Array.newInstance(returnClass, len); for (int i = 0; i < len; i++) { a.values[i].accept(this); if (value == null || value instanceof ExceptionProxy) { return; } try { Array.set(res, i, value); } catch (IllegalArgumentException e) { value = null; // indicates a type mismatch return; } } value = res; } finally { returnClass = returnClassSaved; } } } @SuppressWarnings({"unchecked", "rawtypes"}) public void visitEnum(Attribute.Enum e) { if (returnClass.isEnum()) { String constName = e.value.toString(); try { value = Enum.valueOf((Class)returnClass, constName); } catch (IllegalArgumentException ex) { value = new EnumConstantNotPresentExceptionProxy( (Class>) returnClass, constName); } } else { value = null; // indicates a type mismatch } } public void visitCompound(Attribute.Compound c) { try { Class nested = returnClass.asSubclass(Annotation.class); value = generateAnnotation(c, nested); } catch (ClassCastException ex) { value = null; // indicates a type mismatch } } public void visitError(Attribute.Error e) { if (e instanceof Attribute.UnresolvedClass) value = new MirroredTypeExceptionProxy(((Attribute.UnresolvedClass)e).classType); else value = null; // indicates a type mismatch } /** * Sets "value" to an ExceptionProxy indicating a type mismatch. */ private void typeMismatch(Method method, final Attribute attr) { class AnnotationTypeMismatchExceptionProxy extends ExceptionProxy { static final long serialVersionUID = 269; transient final Method method; AnnotationTypeMismatchExceptionProxy(Method method) { this.method = method; } public String toString() { return ""; // eg: @Anno(value=) } protected RuntimeException generateException() { return new AnnotationTypeMismatchException(method, attr.type.toString()); } } value = new AnnotationTypeMismatchExceptionProxy(method); } } /** * ExceptionProxy for MirroredTypeException. * The toString, hashCode, and equals methods forward to the underlying * type. */ private static final class MirroredTypeExceptionProxy extends ExceptionProxy { static final long serialVersionUID = 269; private transient TypeMirror type; private final String typeString; MirroredTypeExceptionProxy(TypeMirror t) { type = t; typeString = t.toString(); } public String toString() { return typeString; } public int hashCode() { return (type != null ? type : typeString).hashCode(); } public boolean equals(Object obj) { return type != null && obj instanceof MirroredTypeExceptionProxy && type.equals(((MirroredTypeExceptionProxy) obj).type); } protected RuntimeException generateException() { return new MirroredTypeException(type); } // Explicitly set all transient fields. private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); type = null; } } /** * ExceptionProxy for MirroredTypesException. * The toString, hashCode, and equals methods foward to the underlying * types. */ private static final class MirroredTypesExceptionProxy extends ExceptionProxy { static final long serialVersionUID = 269; private transient List types; private final String typeStrings; MirroredTypesExceptionProxy(List ts) { types = ts; typeStrings = ts.toString(); } public String toString() { return typeStrings; } public int hashCode() { return (types != null ? types : typeStrings).hashCode(); } public boolean equals(Object obj) { return types != null && obj instanceof MirroredTypesExceptionProxy && types.equals( ((MirroredTypesExceptionProxy) obj).types); } protected RuntimeException generateException() { return new MirroredTypesException(types); } // Explicitly set all transient fields. private void readObject(ObjectInputStream s) throws IOException, ClassNotFoundException { s.defaultReadObject(); types = null; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy