Przeglądaj źródła

Merge pull request #12296 from richardkchapman/java-import-classname

HPCC-21660 Allow expected classname to be supplied when passing java objects

Reviewed-by: Gavin Halliday <ghalliday@hpccsystems.com>
Gavin Halliday 6 lat temu
rodzic
commit
2337ab6baa

+ 23 - 9
plugins/javaembed/javaembed.cpp

@@ -4159,6 +4159,7 @@ protected:
         try
         {
             StringBuffer classname;
+            StringAttr checkedClassName;
             // Name should be in the form class.method:signature
             const char *funcname = strrchr(importName, '.');
             if (funcname)
@@ -4172,6 +4173,13 @@ protected:
                 nonStatic = true;  // we assume we are going to call a method of a cached object - and we will get the class from that
                 funcname = importName;
             }
+            const char *coloncolon = strstr(funcname, "::");
+            if (coloncolon)
+            {
+                // ClassName::FunctionName syntax - used to check that object passed in is of proper class
+                checkedClassName.set(funcname, coloncolon-funcname);
+                funcname = coloncolon+2;
+            }
             const char *sig = strchr(funcname, ':');
             if (sig)
             {
@@ -4242,15 +4250,8 @@ protected:
             {
                 if (!instance)
                     throw MakeStringException(0, "~ invalid without instance");
-                StringBuffer myClassName;
-                getClassNameForObject(JNIenv, myClassName, instance);
-                const char *shortClassName = strrchr(myClassName, '.');
-                if (shortClassName)
-                    shortClassName++;
-                else
-                    shortClassName = myClassName;
-                if (!streq(methodName+1, shortClassName))
-                    throw MakeStringException(0, "class name %s does not match", shortClassName);
+                if (!checkedClassName)
+                    checkedClassName.set(methodName+1);
                 signature.set("()L");  // We return 0
             }
             else
@@ -4265,6 +4266,19 @@ protected:
                 else
                     javaMethodID = JNIenv->GetStaticMethodID(javaClass, methodName, javaSignature);
             }
+            if (checkedClassName)
+            {
+                StringBuffer myClassName;
+                getClassNameForObject(JNIenv, myClassName, instance);
+                DBGLOG("Checking class name %s matches %s for function %s", myClassName.str(), checkedClassName.str(), methodName.str());
+                const char *shortClassName = strrchr(myClassName, '.');
+                if (shortClassName)
+                    shortClassName++;
+                else
+                    shortClassName = myClassName;
+                if (!streq(checkedClassName, shortClassName))
+                    throw MakeStringException(0, "Object class %s does not match expected class name %s", shortClassName, checkedClassName.str());
+            }
             returnType = strrchr(signature, ')');
             assertex(returnType);  // Otherwise how did Java accept it??
             returnType++;

+ 15 - 14
testing/regress/ecl/javaembed_ex11.ecl

@@ -20,10 +20,10 @@
 
 IMPORT Java;
 
-unsigned persister(integer initial) := EMBED(Java)
-public class persister
+UNSIGNED JavaAccumulator(INTEGER initial) := EMBED(Java)
+public class JavaAccumulator
 {
-  public persister(int initial) { tot = initial; }
+  public JavaAccumulator(int initial) { tot = initial; }
   public synchronized int accumulate(int a)
   {
     tot = tot + a;
@@ -39,17 +39,18 @@ public class persister
 }
 ENDEMBED;
 
-integer accumulate(unsigned p, integer val) := IMPORT(Java, 'accumulate');
-integer clear(unsigned p) := IMPORT(Java, 'clear');
-release(unsigned p) := IMPORT(Java, '~persister'); // After calling this the java object p is no longer usable
+INTEGER accumulate(UNSIGNED p, INTEGER val) := IMPORT(Java, 'JavaAccumulator::accumulate');
+INTEGER clear(UNSIGNED p) := IMPORT(Java, 'JavaAccumulator::clear');
+release(UNSIGNED p) := IMPORT(Java, '~JavaAccumulator'); // After calling this the java object p is no longer usable
 
-p := persister(35) : global;
+a := JavaAccumulator(35) : INDEPENDENT;
 
-sequential(
-  accumulate(p, 1);
-  accumulate(p, 2);
-  accumulate(p, 3);
-  clear(p);
-  accumulate(p, 10);
-  release(p);  
+ORDERED
+(
+  accumulate(a, 1);
+  accumulate(a, 2);
+  accumulate(a, 3);
+  clear(a);
+  accumulate(a, 10);
+  release(a);  
 );

+ 4 - 4
testing/regress/ecl/key/javaembed_ex11.xml

@@ -2,14 +2,14 @@
  <Row><Result_1>36</Result_1></Row>
 </Dataset>
 <Dataset name='Result 2'>
- <Row><Result_2>37</Result_2></Row>
+ <Row><Result_2>38</Result_2></Row>
 </Dataset>
 <Dataset name='Result 3'>
- <Row><Result_3>38</Result_3></Row>
+ <Row><Result_3>41</Result_3></Row>
 </Dataset>
 <Dataset name='Result 4'>
- <Row><Result_4>35</Result_4></Row>
+ <Row><Result_4>41</Result_4></Row>
 </Dataset>
 <Dataset name='Result 5'>
- <Row><Result_5>45</Result_5></Row>
+ <Row><Result_5>10</Result_5></Row>
 </Dataset>