I'm looking into wrapping some java functions in pl/sql but am encountering an ORA-29536 on the colon character in for-loops when loading the java source.
I was hoping to understand why the database has difficulty with this, as it doesn't appear to be misinterpreting the colon and trying to bind, and to get any suggestions on a path forward.
I'd like to avoid refactoring the source to abolish all for-loops, and would like to avoid using the loadjava tool if possible.
Database is 12cR1, with ojdk is 1.6.0_71.
Here's an example.
Given these two trivial hello-world-type classes:
public final class HelloWorld {
public static String greet(final String userName) {
return "Hello " + userName;
}
}
And:
import java.util.Arrays;
import java.util.List;
public final class LoopingTest {
public static String greet(final String userName) {
final List<String> emptyList = Arrays.asList(userName);
for (final String string : emptyList) {
System.out.println(string);
}
return "Hello " + userName;
}
}
When I compile into the database, the first goes in fine and registers JAVA SOURCE
and JAVA CLASS
objects ok (I'm using dynamic SQL and a clob in this example since the eventual target will be >32K characters, with enough @
, &
, etc. to complicate escaping in a raw script):
BEGIN
EXECUTE IMMEDIATE
'
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "HelloWorld" AS
public final class HelloWorld {
public static String greet(final String userName) {
return "Hello " + userName;
}
}
';
END;
/
PL/SQL procedure successfully completed.
But the second fails to import:
BEGIN
EXECUTE IMMEDIATE
'
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "HelloWorld" AS
import java.util.Arrays;
import java.util.List;
public final class LoopingTest {
public static String greet(final String userName) {
final List<String> emptyList = Arrays.asList(userName);
for (final String string : emptyList) {
System.out.println(string);
}
return "Hello " + userName;
}
}
';
END;
/
ERROR at line 1:
ORA-29536: badly formed source: Encountered "final String string :" at line 1,
column 195.
I wondered if there are any changes I can make to coax oracle into loading this.
If using loadjava is the only way to import I can accept that, but I'd prefer loading in one step DDL if possible. Thanks
Oracle seems to be doing some strange pre-processing on the Java code that is flagging the final String string
in the for-each loop as a problem. The error isn't coming from the Java compiler - as you'd expect, since this is valid. I can't see anything about this issue, including on My Oracle Support.
It isn't, as @JonHeller noted in an edit comment, anything to do with the string concatenation, but also isn't anything to do with dynamic SQL - in 11gR2 anyway I still see the same ORA-29536 error if I just run the DDL directly from a SQL prompt, using your second code block.
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "LoopingTest" AS
import java.util.Arrays;
import java.util.List;
public final class LoopingTest {
public static String greet(final String userName) {
final List<String> emptyList = Arrays.asList(userName);
for (final String string : emptyList) {
System.out.println(string);
}
return "Hello " + userName;
}
}
/
Error report -
ORA-29536: badly formed source: Encountered "final String string :" at line 7, column 14.
Was expecting one of:
"boolean" ...
...
As a workaround you can just remove the final
keyword:
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "LoopingTest" AS
import java.util.Arrays;
import java.util.List;
public final class LoopingTest {
public static String greet(final String userName) {
final List<String> emptyList = Arrays.asList(userName);
// remove 'final' to avoid ORA-29536
// for (final String string : emptyList) {
for (String string : emptyList) {
System.out.println(string);
}
return "Hello " + userName;
}
}
/
Java source LoopingTest compiled
Or in your original PL/SQL code:
DECLARE
V_SQL_TEXT CLOB := ' ' ||
'CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "LoopingTest" AS ' ||
'import java.util.Arrays; ' ||
'import java.util.List; ' ||
' ' ||
'public final class LoopingTest { ' ||
'public static String greet(final String userName){ ' ||
'final List<String> emptyList = Arrays.asList(userName); ' ||
-- remove 'final' to avoid ORA-29536
-- 'for (final String string : emptyList){ ' ||
'for (String string : emptyList){ ' ||
'System.out.println(string); ' ||
'} ' ||
'return "Hello " + userName; ' ||
'} ' ||
'} ';
BEGIN
EXECUTE IMMEDIATE V_SQL_TEXT;
END;
/
PL/SQL procedure successfully completed.
You should consider raising a service request with Oracle, to see if they can explain and/or fix the problem.