001 /******************************************************************************* 002 * Copyright (c) 2009 Progress Software, Inc. 003 * Copyright (c) 2004, 2008 IBM Corporation and others. 004 * 005 * All rights reserved. This program and the accompanying materials 006 * are made available under the terms of the Eclipse Public License v1.0 007 * which accompanies this distribution, and is available at 008 * http://www.eclipse.org/legal/epl-v10.html 009 * 010 *******************************************************************************/ 011 package org.fusesource.hawtjni.generator.model; 012 013 import java.lang.annotation.Annotation; 014 import java.lang.reflect.Method; 015 import java.lang.reflect.Modifier; 016 import java.util.ArrayList; 017 import java.util.Arrays; 018 import java.util.HashSet; 019 import java.util.List; 020 021 import org.fusesource.hawtjni.runtime.ArgFlag; 022 import org.fusesource.hawtjni.runtime.JniArg; 023 import org.fusesource.hawtjni.runtime.JniMethod; 024 import org.fusesource.hawtjni.runtime.MethodFlag; 025 import org.fusesource.hawtjni.runtime.T32; 026 027 import static org.fusesource.hawtjni.generator.util.TextSupport.*; 028 import static org.fusesource.hawtjni.runtime.MethodFlag.*; 029 030 /** 031 * 032 * @author <a href="http://hiramchirino.com">Hiram Chirino</a> 033 */ 034 public class ReflectMethod implements JNIMethod { 035 036 private ReflectClass declaringClass; 037 private Method method; 038 039 private List<JNIType> paramTypes32; 040 private List<JNIType> paramTypes64; 041 private List<JNIParameter> parameters; 042 private boolean unique; 043 private JniMethod annotation; 044 045 private boolean allowConversion; 046 private ReflectType returnType; 047 048 private HashSet<MethodFlag> flags; 049 050 public ReflectMethod(ReflectClass declaringClass, Method method) { 051 this.declaringClass = declaringClass; 052 this.method = method; 053 lazyLoad(); 054 } 055 056 public int hashCode() { 057 return method.hashCode(); 058 } 059 060 public boolean equals(Object obj) { 061 if (!(obj instanceof ReflectMethod)) 062 return false; 063 return ((ReflectMethod) obj).method.equals(method); 064 } 065 066 public String toString() { 067 return method.toString(); 068 } 069 070 public Method getWrapedMethod() { 071 return method; 072 } 073 074 /////////////////////////////////////////////////////////////////// 075 // JNIMethod interface methods 076 /////////////////////////////////////////////////////////////////// 077 078 public JNIClass getDeclaringClass() { 079 return declaringClass; 080 } 081 082 public int getModifiers() { 083 return method.getModifiers(); 084 } 085 086 public String getName() { 087 return method.getName(); 088 } 089 090 public List<JNIParameter> getParameters() { 091 lazyLoad(); 092 return parameters; 093 } 094 095 public List<JNIType> getParameterTypes() { 096 lazyLoad(); 097 return paramTypes32; 098 } 099 100 public List<JNIType> getParameterTypes64() { 101 lazyLoad(); 102 return paramTypes64; 103 } 104 105 public JNIType getReturnType32() { 106 lazyLoad(); 107 return returnType.asType32(allowConversion); 108 } 109 110 public JNIType getReturnType64() { 111 lazyLoad(); 112 return returnType.asType64(allowConversion); 113 } 114 115 public boolean getFlag(MethodFlag flag) { 116 lazyLoad(); 117 return flags.contains(flag); 118 } 119 120 public String getCast() { 121 lazyLoad(); 122 String rc = annotation == null ? "" : annotation.cast(); 123 return cast(rc); 124 } 125 126 public boolean isPointer() { 127 lazyLoad(); 128 if( annotation == null ) { 129 return false; 130 } 131 return getFlag(POINTER_RETURN) || ( returnType.getWrappedClass() == Long.TYPE && getCast().endsWith("*)") ); 132 } 133 134 public String getCopy() { 135 lazyLoad(); 136 return annotation == null ? "" : annotation.copy(); 137 } 138 139 public String getAccessor() { 140 lazyLoad(); 141 return annotation == null ? "" : annotation.accessor(); 142 } 143 144 public String getConditional() { 145 lazyLoad(); 146 147 String parentConditional = getDeclaringClass().getConditional(); 148 String myConditional = annotation == null ? null : emptyFilter(annotation.conditional()); 149 if( parentConditional!=null ) { 150 if( myConditional!=null ) { 151 return parentConditional+" && "+myConditional; 152 } else { 153 return parentConditional; 154 } 155 } 156 return myConditional; 157 } 158 159 public boolean isNativeUnique() { 160 lazyLoad(); 161 return unique; 162 } 163 164 public String[] getCallbackTypes() { 165 lazyLoad(); 166 if( annotation==null ) { 167 return new String[0]; 168 } 169 170 JniArg[] callbackArgs = annotation.callbackArgs(); 171 String[] rc = new String[callbackArgs.length]; 172 for (int i = 0; i < rc.length; i++) { 173 rc[i] = callbackArgs[i].cast(); 174 } 175 176 return rc; 177 } 178 179 public ArgFlag[][] getCallbackFlags() { 180 lazyLoad(); 181 if( annotation==null ) { 182 return new ArgFlag[0][]; 183 } 184 185 JniArg[] callbackArgs = annotation.callbackArgs(); 186 ArgFlag[][] rc = new ArgFlag[callbackArgs.length][]; 187 for (int i = 0; i < rc.length; i++) { 188 rc[i] = callbackArgs[i].flags(); 189 } 190 return rc; 191 } 192 193 194 /////////////////////////////////////////////////////////////////// 195 // Helper methods 196 /////////////////////////////////////////////////////////////////// 197 static public String emptyFilter(String value) { 198 if( value==null || value.length()==0 ) 199 return null; 200 return value; 201 } 202 203 private void lazyLoad() { 204 if( flags!=null ) { 205 return; 206 } 207 208 this.annotation = this.method.getAnnotation(JniMethod.class); 209 this.allowConversion = method.getAnnotation(T32.class)!=null; 210 this.flags = new HashSet<MethodFlag>(); 211 if( this.annotation!=null ) { 212 this.flags.addAll(Arrays.asList(this.annotation.flags())); 213 } 214 215 Class<?> returnType = method.getReturnType(); 216 Class<?>[] paramTypes = method.getParameterTypes(); 217 218 this.paramTypes32 = new ArrayList<JNIType>(paramTypes.length); 219 this.paramTypes64 = new ArrayList<JNIType>(paramTypes.length); 220 this.parameters = new ArrayList<JNIParameter>(paramTypes.length); 221 this.returnType = new ReflectType(returnType); 222 223 Annotation[][] parameterAnnotations = method.getParameterAnnotations(); 224 for (int i = 0; i < paramTypes.length; i++) { 225 ReflectParameter parameter = new ReflectParameter(this, i, parameterAnnotations[i]); 226 this.parameters.add(parameter); 227 this.paramTypes32.add( parameter.getType32() ); 228 this.paramTypes64.add( parameter.getType64() ); 229 } 230 231 unique = true; 232 Class<?> parent = ((ReflectClass)declaringClass).getWrapedClass(); 233 String name = method.getName(); 234 for (Method mth : parent.getDeclaredMethods() ) { 235 if ( (mth.getModifiers()&Modifier.NATIVE) != 0 && method!=mth && !method.equals(mth) && name.equals(mth.getName())) { 236 unique = false; 237 break; 238 } 239 } 240 241 } 242 }