Oracle java 存储过程中类解析的困惑
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/597022/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Confusion over class resolution in Oracle java stored procedures
提问by Chris Farmer
I'm trying to use a third-party java library within oracle. The library seems compatible with the same 1.4 version of the jvm that our Oracle 10g server hosts, since it runs fine outside of Oracle, so I feel like I should be able to get this to work. This library ends up making SOAP-based http requests, and I get class resolution errors when I run in Oracle.
我正在尝试在 oracle 中使用第三方 java 库。该库似乎与我们的 Oracle 10g 服务器托管的相同 1.4 版本的 jvm 兼容,因为它在 Oracle 之外运行良好,所以我觉得我应该能够让它工作。该库最终会发出基于 SOAP 的 http 请求,并且在 Oracle 中运行时出现类解析错误。
Here's a line that shows the difference:
这是显示差异的一行:
Class msgfact = Class.forName("com.sun.xml.messaging.saaj.soap.MessageFactoryImpl");
I tried to register these libraries into Oracle with the loadjava utility, and I got what I thought was a successful result:
我尝试使用 loadjava 实用程序将这些库注册到 Oracle 中,得到了我认为成功的结果:
C:\>loadjava -verbose -schema MYUSER -user MYUSER/MYPWD@dbinstance -force saaj-impl.jar
It looks like everything gets loaded, and I can see this MessageFactoryImpl class in that list. But then I try to run this line of code from Oracle SQL (inside another class I wrote and loaded with loadjava), this line throws a ClassNotFoundException (java.lang.ClassNotFoundException: com/sun/xml/messaging/saaj/soap/MessageFactoryImpl).
看起来一切都已加载,我可以在该列表中看到这个 MessageFactoryImpl 类。但是后来我尝试从 Oracle SQL 运行这行代码(在我编写并加载了 loadjava 的另一个类中),这一行抛出 ClassNotFoundException (java.lang.ClassNotFoundException: com/sun/xml/messaging/saaj/soap/MessageFactoryImpl )。
Then I went back and tried to add the "-resolve" switch at the loadjava command line. It acts like these saaj classes are getting registered, but they aren't resolving properly.
然后我返回并尝试在 loadjava 命令行中添加“-resolve”开关。就像这些 saaj 类正在注册,但它们没有正确解析。
How can I successfully get these saaj classes into Oracle, or if for some reason Oracle already has these loaded, how can I convince my own code to successfully use the existing class?
如何将这些 saaj 类成功导入 Oracle,或者如果出于某种原因 Oracle 已经加载了这些类,我如何说服自己的代码成功使用现有类?
FWIW, I already took the steps to make sure that the appropriate socket permissions were granted and my code can successfully make a generic http request to the target url. It just has trouble using the library's SOAP stack to make it happen.
FWIW,我已经采取措施确保授予了适当的套接字权限,并且我的代码可以成功地向目标 url 发出通用 http 请求。它只是在使用库的 SOAP 堆栈来实现它时遇到了麻烦。
EDIT: Here is a sample of my loadjava result. This seems to be showing exactly what's failing, but I'm confused as to why these particular classes aren't being resolved when they seem to be handled properly in the pre-resolution steps. I've eliminated about 80% of the file here, but there are other classes that show the same class resolution issues.
编辑:这是我的 loadjava 结果示例。这似乎准确地显示了失败的原因,但我很困惑,为什么这些特定类在预解析步骤中似乎得到了正确处理,却没有得到解析。我在这里删除了大约 80% 的文件,但还有其他类显示了相同的类解析问题。
arguments: '-verbose' '-schema' 'MYSCHEMA' '-user' 'MYSCHEMA/MYSCHEMA@actest' '-resolve' '-force' 'saaj-impl.jar' [snip] creating : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/EnvelopeFactory loading : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/EnvelopeFactory creating : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/GifDataContentHandler loading : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/GifDataContentHandler creating : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/JpegDataContentHandler loading : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/JpegDataContentHandler creating : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageFactoryImpl loading : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageFactoryImpl creating : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl loading : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl [snip] resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/AttachmentPartImpl resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/Envelope resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/EnvelopeFactory errors : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/EnvelopeFactory ORA-29534: referenced object MYSCHEMA.com/sun/xml/messaging/saaj/soap/SOAPPartImpl could not be resolved resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/GifDataContentHandler resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/JpegDataContentHandler resolving: class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageFactoryImpl errors : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageFactoryImpl ORA-29534: referenced object MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl could not be resolved errors : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl ORA-29534: referenced object MYSCHEMA.com/sun/xml/messaging/saaj/soap/impl/EnvelopeImpl could not be resolved errors : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl ORA-29534: referenced object MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl could not be resolved skipping : class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl [snip] The following operations failed class MYSCHEMA.com/sun/xml/messaging/saaj/soap/EnvelopeFactory: resolution class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageFactoryImpl: resolution class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl: resolution class MYSCHEMA.com/sun/xml/messaging/saaj/soap/MessageImpl: resolution [snip] exiting : Failures occurred during processing
回答by Dave Costa
First of all, verify outside of Oracle that the class you are looking for is actually in that jar file. I expect it is, but it doesn't hurt to check.
首先,在 Oracle 之外验证您要查找的类是否确实在该 jar 文件中。我希望它是,但检查并没有什么坏处。
Then, I would check what classes have been loaded and whether they have valid statuses.
然后,我将检查已加载哪些类以及它们是否具有有效状态。
SELECT object_name, dbms_java.longname(object_name), status
FROM user_objects
WHERE object_type='JAVA CLASS'
ORDER BY 1
You might want to limit this somewhat if there are a lot of classes, e.g.:
如果有很多类,您可能希望对此有所限制,例如:
WHERE dbms_java.longname(object_name) LIKE '%MessageFactoryImpl'
If the class is not there, or it is there with the wrong package name, then the problem is with the loadjava command.
如果该类不存在,或者存在错误的包名,则问题出在 loadjava 命令上。
If the class is there but its status is INVALID, then check USER_ERRORS to see what the errors are. I don't recall if I've done dynamic class loading within Oracle, but I recall that static linking would give errors that implied a class didn't exist when it really existed but had errors.
如果该类存在但其状态为 INVALID,则检查 USER_ERRORS 以查看错误是什么。我不记得我是否在 Oracle 中完成了动态类加载,但我记得静态链接会给出错误,暗示类确实存在但有错误时不存在。
New info after loadjava output posted
发布 loadjava 输出后的新信息
The loadjava output seems inconsistent with your attempt to find the class in the database. If it is being loaded but not resolved, it should still be listed, but with an INVALID status.
loadjava 输出似乎与您在数据库中查找类的尝试不一致。如果正在加载但未解析,则仍应列出它,但状态为 INVALID。
I got the JAR and tried it myself in an empty schema. The class loads but is invalid as expected:
我得到了 JAR 并在一个空的模式中自己尝试了它。该类加载但按预期无效:
dev> select object_name, dbms_java.longname(object_name),status
2 from user_objects
3 where object_name like '%MessageFactoryImpl';
OBJECT_NAME
--------------------------------------------------------------------------------
DBMS_JAVA.LONGNAME(OBJECT_NAME)
--------------------------------------------------------------------------------
STATUS
-------
/3e484eb0_MessageFactoryImpl
com/sun/xml/messaging/saaj/soap/MessageFactoryImpl
INVALID
I then checked what the error were on the class:
然后我检查了课堂上的错误:
dev> alter java class "com/sun/xml/messaging/saaj/soap/MessageFactoryImpl" resolve;
dev> /
Warning: Java altered with compilation errors.
dev> show error
Errors for JAVA CLASS "/3e484eb0_MessageFactoryImpl":
LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0 ORA-29521: referenced name javax/xml/soap/MessageFactory could
not be found
0/0 ORA-29521: referenced name javax/xml/soap/SOAPMessage could not
be found
0/0 ORA-29521: referenced name javax/xml/soap/MimeHeaders could not
be found
0/0 ORA-29521: referenced name javax/xml/soap/SOAPException could not
be found
(These errors would also be listed in USER_ERRORS, assuming resolution was attempted at least once.)
(这些错误也将列在 USER_ERRORS 中,假设至少尝试了一次解决。)
So clearly this class references classes from the base SOAP library. You would have to load that too -- have you done that?
很明显,这个类引用了基本 SOAP 库中的类。你也必须加载它——你这样做了吗?
FYI, when I write some code to do the Class.forName() call, I do get the ClassNotFoundException. Which may seem counter-intuitive since the class object does exist in the schema. However, an invalid class doesn't really "exist" from the point of view of the class loader in Oracle; and in order for the class to be valid Oracle has to be able to resolve all of its references to other classes.
仅供参考,当我编写一些代码来执行 Class.forName() 调用时,我确实得到了 ClassNotFoundException。这可能看起来违反直觉,因为类对象确实存在于模式中。但是,从 Oracle 中的类加载器的角度来看,无效类并不真正“存在”;为了使类有效,Oracle 必须能够解析其对其他类的所有引用。
回答by Brian
Is this the first time your executing Java on the database? Here is hello world implementation to make sure your Oracle JVM is running properly and you have the necessary permissions. You said "my database schema, so I can do whatever I want" -doesn't mean you have the proper grants.
这是您第一次在数据库上执行 Java 吗?这是 hello world 实现,以确保您的 Oracle JVM 正常运行并且您拥有必要的权限。你说“我的数据库模式,所以我可以做任何我想做的事”——并不意味着你有适当的授权。
SQL> create or replace and compile java source named "Hello" as
public class Hello{
public static String world() {
return "Hello World ";
}
};
/
Java created.
Now the wrapper function
现在包装函数
SQL> create or replace function Hello RETURN VARCHAR2
as LANGUAGE JAVA NAME 'Hello.world() return String';
/
Function created.
Now test it
现在测试一下
SQL> select Hello from dual;
HELLO
-----------------------------------
Hello World
回答by TofuBeer
Do this:
做这个:
try
{
System.out.println("Class.forName returned: " +
Class.forName("com.sun.xml.messaging.saaj.soap.MessageFactoryImpl"));
}
catch(final Throwable ex)
{
ex.printStackTrace();
System.exit(1);
}
Just to be 100and10% sure that it is not throwing an exception that is somehow being hidden and that it is really returning null. If it is still the case please let me know (interesting problem if the code above works, but returns null).
只是为了 100 和 10% 确定它没有抛出以某种方式隐藏的异常并且它真的返回 null。如果仍然是这种情况,请告诉我(如果上面的代码有效,但返回空值,这是一个有趣的问题)。
回答by TofuBeer
Try # 3 :-) (I don't use Oracle... but this is a neat problem to debug...)
尝试 # 3 :-)(我不使用 Oracle ......但这是一个很好的调试问题......)
Does the info here on Class.forName in Oracle help?
Oracle 中 Class.forName 上的信息有帮助吗?
http://download.oracle.com/docs/cd/B14117_01/java.101/b12021/appover.htm#i1006547
http://download.oracle.com/docs/cd/B14117_01/java.101/b12021/appover.htm#i1006547
This presents as a ClassLoader issue, so hoepfully the solution is along the same lines as what happens in the "real, non-Oracle" world :-)
这表现为 ClassLoader 问题,因此希望该解决方案与“真实的非 Oracle”世界中发生的情况相同:-)
Edit... another try...
编辑...再试一次...
Ok looking at it some more... what is the output of the following:
好的,再看一下……以下的输出是什么:
System.out.println("vm vendor: " + System.getProperty("java.vendor"));
System.out.println("vm version: " + System.getProperty("java.version"));
System.out.println("class version: " + System.getProperty("java.class.version"));
I am wondering if there is an issue with the class file version - do the class files have a version that cannot be run on the Oracle VM?
我想知道类文件版本是否存在问题 - 类文件是否具有无法在 Oracle VM 上运行的版本?
回答by alexpopescu
Class resolution and loading are complex operations handled by the VM. The algorithm to be used by these 2 operations as described in the spec is left open for VM implementors. My feeling is that in your case the resolution works as the operation checks only the availability of the class itself, while it is failing later when trying to effectively load the class (most probably due to missing dependencies: when loading the class, the VM needs to resolve at least all direct references to other classes). You'll have to make sure that all classes are available to Oracle and performing a quick Google search for ORA-29534 shows tons of people having this problem (and I'm pretty sure somebody figured it out).
类解析和加载是由 VM 处理的复杂操作。规范中描述的这两个操作使用的算法对 VM 实现者开放。我的感觉是,在您的情况下,解析工作是因为操作仅检查类本身的可用性,而稍后在尝试有效加载类时失败(很可能是由于缺少依赖项:加载类时,VM 需要至少解决对其他类的所有直接引用)。您必须确保 Oracle 可以使用所有类,并且在 Google 上快速搜索 ORA-29534 会发现有很多人遇到了这个问题(我很确定有人已经解决了)。
./alex
./亚历克斯
回答by Vineet Reynolds
The saaj-impl.jar is part of the SAAJ component of the Web Services Developer Pack. It has dependencies on other JARs that ship with SAAJ, for instance, it definitely depends on saaj-api.jar and activation.jar, to my knowledge. Of course, saaj-api.jar is bound to depend on a lot of other JARs as well.
saaj-impl.jar 是 Web Services Developer Pack 的 SAAJ 组件的一部分。它依赖于 SAAJ 附带的其他 JAR,例如,据我所知,它绝对依赖于 saaj-api.jar 和 activation.jar。当然,saaj-api.jar 也必然依赖于很多其他的 JAR。
As far as JWSDP 1.5 is concerned, you could find the information in JWSDP 1.5 Release Notesto be useful. JWSDP 1.6 has different JARs in SAAJ I havent found the JWSDP 2.0 Release Notes to be particularly useful in this regard. BTW, JWSDP 2.0 would have different JARs to be placed in the classpath; so the scope of your problem eventually depends on the version of saaj-impl.jar that you use.
就 JWSDP 1.5 而言,您可以在JWSDP 1.5 发行说明中找到有用的信息。JWSDP 1.6 在 SAAJ 中有不同的 JAR 我还没有发现 JWSDP 2.0 发行说明在这方面特别有用。顺便说一句,JWSDP 2.0 会在类路径中放置不同的 JAR;所以你的问题的范围最终取决于你使用的 saaj-impl.jar 的版本。
Just in case you might need it, some documentation is already available on how to load the SOAP client JARs into an Oracle database and to utilize them, in the following pages. I presume these to be different from the SAAJ JARs that comes with your library though.
为了以防万一您可能需要它,在以下页面中已经提供了一些关于如何将 SOAP 客户端 JAR 加载到 Oracle 数据库中并使用它们的文档。我认为这些与您的库附带的 SAAJ JAR 不同。