I have to use some java function in Oracle SQL Developer. But Im having some troubles with java String parameter. I know my code does nothing with this String. It will be.
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED "StringTest" AS
public class StringTest
{
public static int test(String a)
{
return 1;
}
}
/
Which returns:
Java Source StringTest created
Then:
CREATE OR REPLACE FUNCTION F_STRING(input1 in char) return number
as LANGUAGE JAVA NAME 'StringTest.test(String) return int';
Function F_STRING compiled
Now when I try to execute my function:
SELECT F_STRING("some_text") FROM MyTable;
ORA-00904: "some_text": invalid identifier
00000 - "%s: invalid identifier"
When I try using single quote instead of " I get this:
ORA-29531: no method test in class StringTest
29531. 00000 - "no method %s in class %s"
*Cause: An attempt was made to execute a non-existent method in a
Java class.
*Action: Adjust the call or create the specified method.
Same thing happens when I use varchar2 instead of char.
Im sure Im missing something very simple, but can't find solution for like few hours and it already drives me crazy.
When you publishing java method in oracle you have to use full class name. (Canonical Name).
int - is ok ,
String - is not ok.
Change this
CREATE OR REPLACE FUNCTION F_STRING(input1 in char) return number
as LANGUAGE JAVA NAME 'StringTest.test(String) return int';
to this.
CREATE OR REPLACE FUNCTION F_STRING(java.lang.String in char) return number
as LANGUAGE JAVA NAME 'StringTest.test(java.lang.String) return int';
Oracle will not tolerate String use java.lang.String instead.
..Also
Not overuse " sign since this forces you to use exact case call to object, since this is not a big problem with java source it may be with other objects.
CREATE OR REPLACE AND COMPILE JAVA SOURCE NAMED stringtest AS
public class StringTest
{
public static int test(String a)
{
return 1;
}
}
CREATE OR REPLACE FUNCTION F_STRING(input1 in char) return number
as LANGUAGE JAVA NAME 'StringTest.test(java.lang.String) return java.lang.Intiger';
SELECT F_STRING('some_text') FROM dual;
Related
We have a DLL, written in Delphi, being called by a Java app. Initially we had issues when using PChar or ShortString but we changed these to PAnsiChar and all our issues seemed to have been solved.
However, when we started deploying the DLL to our clients, about 50% of the installations get the following error: Invalid memory access.
The very first line in the DLL is to write to our log file but that is not happening which indicated there is a problem between the Delphi and Java datatypes. Does anybody have any ideas as to what Delphi and Java data types work well together?
Delphi DLL code:
function HasCOMConnection(COMServerName: PAnsiChar): Boolean; stdcall;
begin
WriteLog('HasCOMConnection: DLL entered');
Result := HasConnection(COMServerName);
end;
exports
HasCOMConnection;
Calling from Java:
private interface IPMOProcessLabResult extends com.sun.jna.Library {
boolean HasCOMConnection(String COMServerName);
}
private boolean canConnectToCOMServer() {
try {
IPMOProcessLabResult lib = (IPMOProcessLabResult) Native.loadLibrary(config.libraryName, IPMOProcessLabResult.class);
return lib.HasCOMConnection(config.comServerName);
}
catch (Exception ex) {
new AppendLog(new Date(), this.getClass() + "\t" + ex.getClass() + "\t" + "Exception while trying to connect to COMServer: " + ex.getMessage(), "debug");
return false;
}
}
Per the Java JNA documentation, a Java String is converted to a const char* when passed to native code:
Java Strings perform the same function as the native types const char* and const wchar_t* (NUL-terminated arrays). In order to use the proper type when calling a native function, we have to introduce some sort of annotation to identify how the java Stringshould be converted. Java Strings are normally converted to char* since this is the most common usage of strings. Strings are automatically converted to a NUL-terminated array of characross the function call. Returned char* values are automatically copied into a String if the method signature returns String (strdup, for example).
So the use of PAnsiChar on the Delphi side is correct when passing a String as-is.
However, Delphi strings in Delphi 2009+ are natively encoded in UTF-16, same as Java strings. So, it would be more efficient (or at least, no risk of data loss) to use WString on the Java side:
The WString class is used to identify wide character strings. Unicode values are copied directly from the Java char array to a native wchar_t array.
And use PWideChar on the Delphi side to match, eg:
function HasCOMConnection(COMServerName: PWideChar): Boolean; stdcall;
private interface IPMOProcessLabResult extends com.sun.jna.Library {
boolean HasCOMConnection(WString COMServerName);
}
That being said, there are 2 other problems with your code.
Per the same JNA documentation, a Java boolean maps to a native int, not a bool, so your Delphi code needs to use Integer (or Int32) or better LongBool, eg:
function HasCOMConnection(COMServerName: PAnsiChar{or PWideChar}): LongBool; stdcall;
More importantly, if a native library uses the stdcall calling convention, you have to extend IPMOProcessLabResult from com.sun.jna.win32.StdCallLibrary, eg:
private interface IPMOProcessLabResult extends com.sun.jna.StdCallLibrary
Otherwise, if you extend from com.sun.jna.Library then you need to use cdecl on the native side:
function HasCOMConnection(COMServerName: PAnsiChar{or PWideChar}): LongBool; cdecl;
I try to write an Wrapper function in PL/SQl to call the encode function of the org.apache.commons.codec.language.colognephonetic Class, as described on official apache commons wiki. Cologne Phonetic Apache
Wrapper function looks like following:
function get_phonetic_string(i_string VARCHAR2) RETURN VARCHAR2 AS LANGUAGE java name 'org.apache.commons.codec.language.ColognePhonetic.encode(
java.lang.String
) return java.lang.String';
But, when I execute my wrapper function, I got following error: ORA-29531: no method encode in class org/apache/commons/codec/language/ColognePhonetic. But obviously there is a encode function.
Could someone help me to figure out what I'm doing wrong?
First, make sure the org.apache.commons.codec.language.ColognePhonetic class is in the database (it probably will not be).
SELECT *
FROM ALL_OBJECTS
WHERE OBJECT_TYPE LIKE '%JAVA%'
AND LOWER( OBJECT_NAME ) LIKE '%colognephonetic%';
Should return a row if it exists (may need to be run as a privileged user).
If it does not exist then you will need to use the loadjava application to load the jar library containing the classes.
Then write a wrapper to create a static function that makes an instance of the class (untested):
CREATE JAVA SOURCE NAMED Phonetics AS
import org.apache.commons.codec.language.ColognePhonetic;
public class Phonetics {
public static String encode(
final String text
){
final ColognePhonetic cp = new ColognePhonetic();
return cp.encode( text );
}
}
/
CREATE FUNCTION get_phonetic_string(i_string VARCHAR2) RETURN VARCHAR2 AS
LANGUAGE JAVA NAME 'Phonetics.encode( java.lang.String ) return java.lang.String';
I'm developing an Unity(Unity3D 5.3.5f1) project with using Java library converted into dll with IKVM 8.1 RC0 (Additionally using VS for c# development)
I converted several related jars into one dll file. There was no warning or error in converting sequence. And I put them in Assets folder in Unity project.
I tried to run my java code in C#.
This is my C# code where executes java logics (Actually shorten a lot)
using UnityEngine;
using com.mypackage.hierarchy1;
using com.mypackage.hierarchy2; // Same as the package name from Java
public class Test : MonoBehaviour {
...... // several variables
private Class1 var1;
private Class2 var2;
// note that, Class1 and Class2 are the same name used in Java
void Start() {
var1 = new Class1();
var2 = new Class2();
}
void Update() {
method1(certain_param_in_int);
}
......
void method1(int param) {
method2(param, param2, param3,...);
}
void method2(int param, string param2, int param3, int param4) {
var1.method_v1(param, param2,...); // Works well with no problem
var2.initialize("str", var1.getResult(), "anotherstr");
var2.run(); // This method occurs the problem
}
}
The problem is that when var2.run() is executed. method from var1 has no problem. I checked the result was correct. Anyway, var2.run() shows NullReferenceException as below
NullReferenceException: Object reference not set to an instance of an object
com.mypackage.hierarchy2.Class2.run ()
Test.method2 (Int32 param, System.String param2, Int32 param3, Int32 param4) (at Assets/Scripts/Test.cs:93)
Test.method1 (Int32 param) (at Assets/Scripts/Test.cs:66)
Test.Update () (at Assets/Scripts/Test.cs:33)
So, I tested whether it is null or not by checking var2 == null and also var2.Equals(null) with Debug.Log() just before calling val2.run(), but all of them showed 'False'. They are not null.
What is the problem? Should I change Java side code and re-generate dll?
Thanks.
p.s. My java side code uses java.util.logging.Logger and related with other java project. (which is also referenced when converting jar into dll, as I said in second sentence of the question)
p.s.2. I'm sorry but I can't open java codes here because it is confidential code
I found that it was an error of our own code, but not java code itself. configurations.
Situation: I have a library of JNI files, the library is comprised of several functions that are called by the main header file in that JNI library (i.e., code1.h). I have a Java file (i.e., code2.java) that I want to pass to and from JNI header file (code1.h). I created a source code for the (code1.h) called (code1.c).
My question is: Does (code1.h), (code1.c), and (code2.java) have to be the same name for the communication between the JNI and the java?
EDIT: So (code1.h), (code1.c), and (code1.java) all have to be the same name in order for the (code1.java) to pass strings to/from (code1.c)/(code1.h)? And it is not possible to have (code2.java) pass strings to/from (code1.c)/(code1.h) because they are not named the same, is this correct?
For instance,
public class code1 { /*this is code2.java, but should the name be changed to (code1.java) to match that of the JNI?*/
static {
System.loadLibrary("myjni");
}
to pass strings to code1.h/code1.c
This will be compiled for android using Linux Debian"Wheezy" and Eclipse with Android SDK and NDK
While Java requires a match between compilation unit name (SomeClass.java being the name and public class SomeClass{ being the declaration, C does not require this.
You may name the C source and header files as you see fit as long as the function names/exported symbol names match the name of the native method on the java side. For example:
//JavaClass.java
public class JavaClass{
public native String getAString(String in);
}
And header would be:
// any name
JNIEXPORT jstring JNICALL
Java_JavaClass_getAString(JNIEnv *, jobject, jstring);
with matching C files. You could name this header catsMakeTheWorldGoRound.h for all Java cares.
Here is an example of what your "JNI object" should look like.
//In my experience, it is better to put the JNI object into a separate package.
package org.example;
public class Code1
{
static
{
// On a Linux system, the actual name of the library
// is prefixed with "lib" and suffixed with ".so"
// -- e.g. "myjni-java.so"
// Windows looks for "myjni-java.dll"
//
// On a Windows system, we also need to load the prequisite
// libraries first. (Linux loaders do this automatically).
//
String osname = System.getProperty("os.name");
if (osname.indexOf("win") > -1 || osname.indexOf("Win") > -1)
{
System.loadLibrary("myjni");
}
System.loadLibrary("myjni-java");
}
// Now we declare the C functions which we will use in our Java code.
public static native void foo(int bar);
public static native int bar(String foo);
//...
}
Given that you have compiled your JNI library correctly, you can then call the C functions from other Java classes like this:
//Again, in my experience, it is better to explicitly give the package name here.
org.example.Code1 Code1= new org.example.Code1();
Code1.foo(123);
int a= Code1.bar("Hello C function from Java function!");
Does this help you with your question? (I am not an expert in JNI, so I might not be able to help further.)
I am brand new to Java. I am having an issue compiling a basic java program, and I am trying to understand why. (note that the TextIO class in the code is used in book I am studying to simplify the IO process, I don't believe that is where the issue is) Here is my code:
public class ProcessSales {
public static void main(String[] args) {
String ln;
String tmp;
int i;
int noval;
TextIO.readFile("sales.dat");
while (TextIO.eof() == false){
ln = TextIO.getln();
for (i = 0; i < ln.length(); i++) {
if (ln.charAt(i) == ':'){
tmp = ln.subString(i + 1);
}
} // end line for loop
try {
System.out.printf("%8.2f\n", Double(tmp.trim()));
}
catch (NumberFormatException e) {
noval++;
}
} // end of file while loop
System.out.printf("\nThere were a total of %d cities that didnt have data\n", noval);
} // end of main subroutine
} // end of ProcessSales class
The compile error I get is as follows:
[seldon#PrimeRadiant Exercises]$ javac ProcessSales.java
ProcessSales.java:15: cannot find symbol
symbol : method subString(int)
location: class java.lang.String
tmp = ln.subString(i + 1);
^
ProcessSales.java:20: cannot find symbol
symbol : method Double(java.lang.String)
location: class ProcessSales
System.out.printf("%8.2f\n", Double(tmp.trim()));
^
2 errors
Ive declared ln as a String object. The subString method is straight out of the java api for a String object. I'm not understanding why I'm getting a cannot find symbol compile error, especially if it lists the method signature and location right below the error.
I marked the questions as homework, since I am working out of a textbook, and I am looking to understand the issue, rather than a flat solution. However it is self study, and not part of any actual class (right now).
The great thing about the Java compiler is, it gives you alot of information to use in determining where problems exist in your code. For you, the first problem is here:
tmp = ln.subString(i + 1);
In this case you capitalized a letter that you shouldn't have. It should be:
tmp = ln.substring(i + 1);
Whenever you see compiler output saying 'cannot find symbol' its because the Java compiler could not find a method matching the outputted name, either due to a syntax error or missing dependency. For your second problem, you didn't post the appropriate code, but from the error message I can see you are missing the new keyword.
System.out.printf("%8.2f\n", Double(tmp.trim()));
Should be
System.out.printf("%8.2f\n", new Double(tmp.trim()));
If this is not your first programming language then I would recommend using an IDE like Eclipse, as it will give you auto-completion and syntax checking. It's a great tool for quickly learning the API's for the language. However if Java is your first programming language please do continue without hand-holding, as the hard knocks will cement in the lessons learned, faster.
I haven't verified any of this, I just looked at the source and the error messages.
The first error seems to be a case error. The Java String class does not have a subString method, it has a substring method, note the lowercase s. Reference
The second error would probably be resolved if you used new Double or Double.valueof instead of Double. This is because you are probably trying to construct a new Double object and using new operator or the valueof method in the Double class do this for you. Reference
In Java, method names are case sensitive. Check back with the String API specification for the correct "casing".
Regarding your first error, you have a typo. It should be ln.substring(i+1) not ln.subString(i+1). All source code text in Java is case sensitive.
Regarding your second error, you need to use the new keyword to instantiate the Double object. Without new, the compiler is not looking for the constructor; instead it is looking for a method Double within your ProcessSales class and cannot find it.