|
41 | 41 | import java.awt.image.ImageProducer; |
42 | 42 | import java.awt.image.RGBImageFilter; |
43 | 43 | import java.io.*; |
| 44 | +import java.lang.reflect.Method; |
44 | 45 |
|
| 46 | +import java.net.MalformedURLException; |
45 | 47 | import java.net.URL; |
46 | 48 | import java.net.URLClassLoader; |
47 | 49 | import java.nio.channels.FileChannel; |
@@ -3972,6 +3974,117 @@ static String xmlize(String s) { |
3972 | 3974 | } |
3973 | 3975 |
|
3974 | 3976 |
|
| 3977 | + @Override |
| 3978 | + protected String registerNativeImplementationsAndCreateStubs(ClassLoader parentClassLoader, File stubDir, File... classesDirectory) throws MalformedURLException, IOException { |
| 3979 | + Class[] discoveredNativeInterfaces = findNativeInterfaces(parentClassLoader, classesDirectory); |
| 3980 | + String registerNativeFunctions = ""; |
| 3981 | + if (discoveredNativeInterfaces != null && discoveredNativeInterfaces.length > 0) { |
| 3982 | + for (Class n : discoveredNativeInterfaces) { |
| 3983 | + registerNativeFunctions += " NativeLookup.register(" + n.getName() + ".class, " |
| 3984 | + + n.getName() + "Stub.class" + ");\n"; |
| 3985 | + } |
| 3986 | + } |
| 3987 | + |
| 3988 | + if (discoveredNativeInterfaces != null && discoveredNativeInterfaces.length > 0) { |
| 3989 | + for (Class currentNative : discoveredNativeInterfaces) { |
| 3990 | + File folder = new File(stubDir, currentNative.getPackage().getName().replace('.', File.separatorChar)); |
| 3991 | + folder.mkdirs(); |
| 3992 | + File javaFile = new File(folder, currentNative.getSimpleName() + "Stub.java"); |
| 3993 | + |
| 3994 | + String javaImplSourceFile = "package " + currentNative.getPackage().getName() + ";\n\n" |
| 3995 | + + "import com.codename1.ui.PeerComponent;\n\n" |
| 3996 | + + "public class " + currentNative.getSimpleName() + "Stub implements " + currentNative.getSimpleName() + "{\n" |
| 3997 | + + " private final Object impl = createImpl();\n\n" |
| 3998 | + + " private static Object createImpl() {\n" |
| 3999 | + + " try {\n" |
| 4000 | + + " return Class.forName(\"" + currentNative.getName() + getImplSuffix() + "\").newInstance();\n" |
| 4001 | + + " } catch (Throwable t) {\n" |
| 4002 | + + " throw new RuntimeException(\"Failed to instantiate native implementation for " + currentNative.getName() + "\", t);\n" |
| 4003 | + + " }\n" |
| 4004 | + + " }\n\n" |
| 4005 | + + " private Object __cn1Invoke(String methodName, Object[] args) {\n" |
| 4006 | + + " try {\n" |
| 4007 | + + " java.lang.reflect.Method[] methods = impl.getClass().getMethods();\n" |
| 4008 | + + " for (java.lang.reflect.Method method : methods) {\n" |
| 4009 | + + " if (method.getName().equals(methodName) && method.getParameterTypes().length == args.length) {\n" |
| 4010 | + + " return method.invoke(impl, args);\n" |
| 4011 | + + " }\n" |
| 4012 | + + " }\n" |
| 4013 | + + " throw new RuntimeException(methodName + \" with \" + args.length + \" args\");\n" |
| 4014 | + + " } catch (Throwable t) {\n" |
| 4015 | + + " throw new RuntimeException(\"Failed to invoke native method \" + methodName, t);\n" |
| 4016 | + + " }\n" |
| 4017 | + + " }\n\n"; |
| 4018 | + |
| 4019 | + for (Method m : currentNative.getMethods()) { |
| 4020 | + String name = m.getName(); |
| 4021 | + if (name.equals("hashCode") || name.equals("equals") || name.equals("toString")) { |
| 4022 | + continue; |
| 4023 | + } |
| 4024 | + |
| 4025 | + Class returnType = m.getReturnType(); |
| 4026 | + |
| 4027 | + javaImplSourceFile += " public " + returnType.getSimpleName() + " " + name + "("; |
| 4028 | + Class[] params = m.getParameterTypes(); |
| 4029 | + String args = ""; |
| 4030 | + if (params != null && params.length > 0) { |
| 4031 | + for (int iter = 0; iter < params.length; iter++) { |
| 4032 | + if (iter > 0) { |
| 4033 | + javaImplSourceFile += ", "; |
| 4034 | + args += ", "; |
| 4035 | + } |
| 4036 | + javaImplSourceFile += params[iter].getSimpleName() + " param" + iter; |
| 4037 | + if (params[iter].getName().equals("com.codename1.ui.PeerComponent")) { |
| 4038 | + args += convertPeerComponentToNative("param" + iter); |
| 4039 | + } else { |
| 4040 | + args += "param" + iter; |
| 4041 | + } |
| 4042 | + } |
| 4043 | + } |
| 4044 | + javaImplSourceFile += ") {\n"; |
| 4045 | + String invocationExpression = "__cn1Invoke(\"" + name + "\", new Object[]{" + args + "})"; |
| 4046 | + if (Void.class == returnType || Void.TYPE == returnType) { |
| 4047 | + javaImplSourceFile += " " + invocationExpression + ";\n }\n\n"; |
| 4048 | + } else { |
| 4049 | + if (returnType.getName().equals("com.codename1.ui.PeerComponent")) { |
| 4050 | + javaImplSourceFile += " return " + generatePeerComponentCreationCode(invocationExpression) + ";\n }\n\n"; |
| 4051 | + } else if (returnType.isPrimitive()) { |
| 4052 | + if (returnType == Boolean.TYPE) { |
| 4053 | + javaImplSourceFile += " return ((Boolean)" + invocationExpression + ").booleanValue();\n }\n\n"; |
| 4054 | + } else if (returnType == Integer.TYPE) { |
| 4055 | + javaImplSourceFile += " return ((Integer)" + invocationExpression + ").intValue();\n }\n\n"; |
| 4056 | + } else if (returnType == Long.TYPE) { |
| 4057 | + javaImplSourceFile += " return ((Long)" + invocationExpression + ").longValue();\n }\n\n"; |
| 4058 | + } else if (returnType == Byte.TYPE) { |
| 4059 | + javaImplSourceFile += " return ((Byte)" + invocationExpression + ").byteValue();\n }\n\n"; |
| 4060 | + } else if (returnType == Short.TYPE) { |
| 4061 | + javaImplSourceFile += " return ((Short)" + invocationExpression + ").shortValue();\n }\n\n"; |
| 4062 | + } else if (returnType == Character.TYPE) { |
| 4063 | + javaImplSourceFile += " return ((Character)" + invocationExpression + ").charValue();\n }\n\n"; |
| 4064 | + } else if (returnType == Float.TYPE) { |
| 4065 | + javaImplSourceFile += " return ((Float)" + invocationExpression + ").floatValue();\n }\n\n"; |
| 4066 | + } else if (returnType == Double.TYPE) { |
| 4067 | + javaImplSourceFile += " return ((Double)" + invocationExpression + ").doubleValue();\n }\n\n"; |
| 4068 | + } else { |
| 4069 | + javaImplSourceFile += " return (" + returnType.getSimpleName() + ")" + invocationExpression + ";\n }\n\n"; |
| 4070 | + } |
| 4071 | + } else { |
| 4072 | + javaImplSourceFile += " return (" + returnType.getSimpleName() + ")" + invocationExpression + ";\n }\n\n"; |
| 4073 | + } |
| 4074 | + } |
| 4075 | + } |
| 4076 | + |
| 4077 | + javaImplSourceFile += "}\n"; |
| 4078 | + |
| 4079 | + try (FileOutputStream out = new FileOutputStream(javaFile)) { |
| 4080 | + out.write(javaImplSourceFile.getBytes(StandardCharsets.UTF_8)); |
| 4081 | + } |
| 4082 | + } |
| 4083 | + } |
| 4084 | + |
| 4085 | + return registerNativeFunctions; |
| 4086 | + } |
| 4087 | + |
3975 | 4088 | @Override |
3976 | 4089 | protected String generatePeerComponentCreationCode(String methodCallString) { |
3977 | 4090 | return "PeerComponent.create(" + methodCallString + ")"; |
|
0 commit comments