1 /*
2  * The contents of this file is dual-licensed under 2
3  * alternative Open Source/Free licenses: LGPL 2.1 or later and
4  * Apache License 2.0. (starting with JNA version 4.0.0).
5  *
6  * You can freely decide which license you want to apply to
7  * the project.
8  *
9  * You may obtain a copy of the LGPL License at:
10  *
11  * http://www.gnu.org/licenses/licenses.html
12  *
13  * A copy is also included in the downloadable source code package
14  * containing JNA, in file "LGPL2.1".
15  *
16  * You may obtain a copy of the Apache License at:
17  *
18  * http://www.apache.org/licenses/
19  *
20  * A copy is also included in the downloadable source code package
21  * containing JNA, in file "AL2.0".
22  */
23 package com.sun.jna;
24 
25 import java.lang.reflect.Method;
26 
27 /**
28  * Class for checking if a method has vararg parameters.
29  * Use method {@link VarArgsChecker#create() create()} to create an instance
30  * of this class. How the returned instance work depends on the capabilities
31  * of the underlying JVM implementation. On older versions of the VM not supporting
32  * varargs, the returned VarArgsChecker will always return <code>false</code>
33  * on calls to {@link VarArgsChecker#isVarArgs(Method) isVarArgs(Method)}.
34  * @author Max Bureck
35  */
36 abstract class VarArgsChecker {
37 
VarArgsChecker()38     private VarArgsChecker() {
39     }
40 
41     /**
42      * Implementation actually using Method.isVarArgs()
43      */
44     private static final class RealVarArgsChecker extends VarArgsChecker {
45 
isVarArgs(Method m)46         boolean isVarArgs(Method m) {
47             return m.isVarArgs();
48         }
49 
fixedArgs(Method m)50         int fixedArgs(Method m) {
51             // In Java, final argument contains all "varargs"
52             return m.isVarArgs() ? m.getParameterTypes().length - 1 : 0;
53         }
54     }
55 
56     /**
57      * Implementation always returning false when {@link NoVarArgsChecker#isVarArgs(Method)}
58      * is called. This implementation will be chosen, if {@link Method#isVarArgs()} is not available
59      */
60     private static final class NoVarArgsChecker extends VarArgsChecker {
61 
isVarArgs(Method m)62         boolean isVarArgs(Method m) {
63             return false;
64         }
65 
fixedArgs(Method m)66         int fixedArgs(Method m) {
67             return 0;
68         }
69     }
70 
71     /**
72      * Creates a new instance of a concrete subclass of VarArgsChecker, depending
73      * if {@link Method#isVarArgs()} exists.
74      * @return new instance of concrete VarArgsChecker subclass
75      */
create()76     static VarArgsChecker create() {
77         try {
78             // check if Method#isVarArgs() exists
79             final Method isVarArgsMethod = Method.class.getMethod("isVarArgs", new Class[0]);
80             if(isVarArgsMethod != null) {
81                 // if it exitsts, return new instance of RealVarArgsChecker
82                 return new RealVarArgsChecker();
83             } else {
84                 return new NoVarArgsChecker();
85             }
86         } catch (NoSuchMethodException e) {
87             return new NoVarArgsChecker();
88         } catch (SecurityException e) {
89             return new NoVarArgsChecker();
90         }
91     }
92 
93     /**
94      * Checks if the given method was declared to take a variable number of arguments.
95      * @param m Method to be checked
96      * @return <code>true</code> if the given method takes a variable number of arguments, <code>false</code> otherwise.
97      */
isVarArgs(Method m)98     abstract boolean isVarArgs(Method m);
99 
100     /**
101      * If variadic, returns the number of fixed arguments to the method.
102      * @param m Method to be checked
103      * @return Number of fixed arguments if the given method takes a variable number of arguments, zero otherwise.
104      */
fixedArgs(Method m)105     abstract int fixedArgs(Method m);
106 }
107