001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common Development
008: * and Distribution License("CDDL") (collectively, the "License"). You
009: * may not use this file except in compliance with the License. You can obtain
010: * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
011: * or glassfish/bootstrap/legal/LICENSE.txt. See the License for the specific
012: * language governing permissions and limitations under the License.
013: *
014: * When distributing the software, include this License Header Notice in each
015: * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
016: * Sun designates this particular file as subject to the "Classpath" exception
017: * as provided by Sun in the GPL Version 2 section of the License file that
018: * accompanied this code. If applicable, add the following below the License
019: * Header, with the fields enclosed by brackets [] replaced by your own
020: * identifying information: "Portions Copyrighted [year]
021: * [name of copyright owner]"
022: *
023: * Contributor(s):
024: *
025: * If you wish your version of this file to be governed by only the CDDL or
026: * only the GPL Version 2, indicate your decision by adding "[Contributor]
027: * elects to include this software in this distribution under the [CDDL or GPL
028: * Version 2] license." If you don't indicate a single choice of license, a
029: * recipient has the option to distribute your version of this file under
030: * either the CDDL, the GPL Version 2 or to extend the choice of license to
031: * its licensees as provided above. However, if you add GPL Version 2 code
032: * and therefore, elected the GPL Version 2 license, then the option applies
033: * only if the new code is made subject to such option by the copyright
034: * holder.
035: */
036:
037: package com.sun.xml.bind.v2.model.annotation;
038:
039: import java.lang.annotation.Annotation;
040: import java.lang.reflect.InvocationHandler;
041: import java.lang.reflect.InvocationTargetException;
042: import java.lang.reflect.Method;
043: import java.lang.reflect.Proxy;
044: import java.lang.reflect.Modifier;
045: import java.util.HashMap;
046: import java.util.Map;
047:
048: import com.sun.xml.bind.v2.runtime.Location;
049:
050: /**
051: * {@link Annotation} that also implements {@link Locatable}.
052: *
053: * @author Kohsuke Kawaguchi
054: */
055: public class LocatableAnnotation implements InvocationHandler,
056: Locatable, Location {
057: private final Annotation core;
058:
059: private final Locatable upstream;
060:
061: /**
062: * Wraps the annotation into a proxy so that the returned object will also implement
063: * {@link Locatable}.
064: */
065: public static <A extends Annotation> A create(A annotation,
066: Locatable parentSourcePos) {
067: if (annotation == null)
068: return null;
069: Class<? extends Annotation> type = annotation.annotationType();
070: if (quicks.containsKey(type)) {
071: // use the existing proxy implementation if available
072: return (A) quicks.get(type).newInstance(parentSourcePos,
073: annotation);
074: }
075:
076: // otherwise take the slow route
077:
078: ClassLoader cl = LocatableAnnotation.class.getClassLoader();
079:
080: try {
081: Class loadableT = Class.forName(type.getName(), false, cl);
082: if (loadableT != type)
083: return annotation; // annotation type not loadable from this class loader
084:
085: return (A) Proxy.newProxyInstance(cl, new Class[] { type,
086: Locatable.class }, new LocatableAnnotation(
087: annotation, parentSourcePos));
088: } catch (ClassNotFoundException e) {
089: // annotation not loadable
090: return annotation;
091: } catch (IllegalArgumentException e) {
092: // Proxy.newProxyInstance throws this if it cannot resolve this annotation
093: // in this classloader
094: return annotation;
095: }
096:
097: }
098:
099: LocatableAnnotation(Annotation core, Locatable upstream) {
100: this .core = core;
101: this .upstream = upstream;
102: }
103:
104: public Locatable getUpstream() {
105: return upstream;
106: }
107:
108: public Location getLocation() {
109: return this ;
110: }
111:
112: public Object invoke(Object proxy, Method method, Object[] args)
113: throws Throwable {
114: try {
115: if (method.getDeclaringClass() == Locatable.class)
116: return method.invoke(this , args);
117: if (Modifier.isStatic(method.getModifiers()))
118: // malicious code can pass in a static Method object.
119: // doing method.invoke() would end up executing it,
120: // so we need to protect against it.
121: throw new IllegalArgumentException();
122:
123: return method.invoke(core, args);
124: } catch (InvocationTargetException e) {
125: if (e.getTargetException() != null)
126: throw e.getTargetException();
127: throw e;
128: }
129: }
130:
131: public String toString() {
132: return core.toString();
133: }
134:
135: /**
136: * List of {@link Quick} implementations keyed by their annotation type.
137: */
138: private static final Map<Class, Quick> quicks = new HashMap<Class, Quick>();
139:
140: static {
141: for (Quick q : Init.getAll()) {
142: quicks.put(q.annotationType(), q);
143: }
144: }
145: }
|