1 /*
2  * Copyright (c) 2009, 2015, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 /*
27  * This file is available under and governed by the GNU General Public
28  * License version 2 only, as published by the Free Software Foundation.
29  * However, the following notice accompanied the original version of this
30  * file:
31  *
32  * The MIT License
33  *
34  * Copyright (c) 2004-2015 Paul R. Holser, Jr.
35  *
36  * Permission is hereby granted, free of charge, to any person obtaining
37  * a copy of this software and associated documentation files (the
38  * "Software"), to deal in the Software without restriction, including
39  * without limitation the rights to use, copy, modify, merge, publish,
40  * distribute, sublicense, and/or sell copies of the Software, and to
41  * permit persons to whom the Software is furnished to do so, subject to
42  * the following conditions:
43  *
44  * The above copyright notice and this permission notice shall be
45  * included in all copies or substantial portions of the Software.
46  *
47  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
48  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
49  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
50  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
51  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
52  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
53  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
54  */
55 
56 package jdk.internal.joptsimple.internal;
57 
58 import java.lang.reflect.Constructor;
59 import java.lang.reflect.InvocationTargetException;
60 import java.lang.reflect.Method;
61 
62 import static java.lang.reflect.Modifier.*;
63 
64 import jdk.internal.joptsimple.ValueConverter;
65 
66 import static jdk.internal.joptsimple.internal.Classes.*;
67 
68 /**
69  * Helper methods for reflection.
70  *
71  * @author <a href="mailto:pholser@alumni.rice.edu">Paul Holser</a>
72  */
73 public final class Reflection {
Reflection()74     private Reflection() {
75         throw new UnsupportedOperationException();
76     }
77 
78     /**
79      * Finds an appropriate value converter for the given class.
80      *
81      * @param <V> a constraint on the class object to introspect
82      * @param clazz class to introspect on
83      * @return a converter method or constructor
84      */
findConverter( Class<V> clazz )85     public static <V> ValueConverter<V> findConverter( Class<V> clazz ) {
86         Class<V> maybeWrapper = wrapperOf( clazz );
87 
88         ValueConverter<V> valueOf = valueOfConverter( maybeWrapper );
89         if ( valueOf != null )
90             return valueOf;
91 
92         ValueConverter<V> constructor = constructorConverter( maybeWrapper );
93         if ( constructor != null )
94             return constructor;
95 
96         throw new IllegalArgumentException( clazz + " is not a value type" );
97     }
98 
valueOfConverter( Class<V> clazz )99     private static <V> ValueConverter<V> valueOfConverter( Class<V> clazz ) {
100         try {
101             Method valueOf = clazz.getMethod( "valueOf", String.class );
102             if ( meetsConverterRequirements( valueOf, clazz ) )
103                 return new MethodInvokingValueConverter<>( valueOf, clazz );
104 
105             return null;
106         } catch ( NoSuchMethodException ignored ) {
107             return null;
108         }
109     }
110 
constructorConverter( Class<V> clazz )111     private static <V> ValueConverter<V> constructorConverter( Class<V> clazz ) {
112         try {
113             return new ConstructorInvokingValueConverter<>( clazz.getConstructor( String.class ) );
114         } catch ( NoSuchMethodException ignored ) {
115             return null;
116         }
117     }
118 
119     /**
120      * Invokes the given constructor with the given arguments.
121      *
122      * @param <T> constraint on the type of the objects yielded by the constructor
123      * @param constructor constructor to invoke
124      * @param args arguments to hand to the constructor
125      * @return the result of invoking the constructor
126      * @throws ReflectionException in lieu of the gaggle of reflection-related exceptions
127      */
instantiate( Constructor<T> constructor, Object... args )128     public static <T> T instantiate( Constructor<T> constructor, Object... args ) {
129         try {
130             return constructor.newInstance( args );
131         } catch ( Exception ex ) {
132             throw reflectionException( ex );
133         }
134     }
135 
136     /**
137      * Invokes the given static method with the given arguments.
138      *
139      * @param method method to invoke
140      * @param args arguments to hand to the method
141      * @return the result of invoking the method
142      * @throws ReflectionException in lieu of the gaggle of reflection-related exceptions
143      */
invoke( Method method, Object... args )144     public static Object invoke( Method method, Object... args ) {
145         try {
146             return method.invoke( null, args );
147         } catch ( Exception ex ) {
148             throw reflectionException( ex );
149         }
150     }
151 
152     @SuppressWarnings( "unchecked" )
convertWith( ValueConverter<V> converter, String raw )153     public static <V> V convertWith( ValueConverter<V> converter, String raw ) {
154         return converter == null ? (V) raw : converter.convert( raw );
155     }
156 
meetsConverterRequirements( Method method, Class<?> expectedReturnType )157     private static boolean meetsConverterRequirements( Method method, Class<?> expectedReturnType ) {
158         int modifiers = method.getModifiers();
159         return isPublic( modifiers ) && isStatic( modifiers ) && expectedReturnType.equals( method.getReturnType() );
160     }
161 
reflectionException( Exception ex )162     private static RuntimeException reflectionException( Exception ex ) {
163         if ( ex instanceof IllegalArgumentException )
164             return new ReflectionException( ex );
165         if ( ex instanceof InvocationTargetException )
166             return new ReflectionException( ex.getCause() );
167         if ( ex instanceof RuntimeException )
168             return (RuntimeException) ex;
169 
170         return new ReflectionException( ex );
171     }
172 }
173