I'm having some problems at runtime with some of my generated protocol buffer classes.
My project layout is as follows:
module/
protobuf-api/
proto/
com/foo/api/Service.proto
com/foo/shared/Shared.proto
org/bar/api/Message1.proto
org/bar/api/Message2.proto
The Service.proto file depends on Shared.proto and some of the Message*.proto files. From the protobuf-api directory, I run the following command to compile:
find . -name *.proto -exec protoc --java_out=java -I=proto {} \;
When I attempt to run my Service, I get the following exception:
java.lang.ExceptionInInitializerError
at com.linkedin.history.api.protobuf.HistoryServiceProtos$HistoryServiceQuery.(HistoryServiceProtos.java:544)
at com.linkedin.history.api.serializer.HistoryServiceSerializer.serialize(HistoryServiceSerializer.java:47)
at test.history.serializer.TestSerializer.testHistoryServiceQuery(TestSerializer.java:38)
at test.fwk.util.core.BaseTestSuiteCore.run(BaseTestSuiteCore.java:304)
at test.fwk.util.core.BaseTestSuiteConf.run(BaseTestSuiteConf.java:186)
at test.fwk.lispring.BaseTestSuite.run(BaseTestSuite.java:232)
at test.fwk.lispring.BaseTestSuite.callAppropriateRun(BaseTestSuite.java:265)
at test.fwk.util.core.BaseTestSuiteCore.run(BaseTestSuiteCore.java:199)
Caused by: java.lang.IllegalArgumentException: Invalid embedded descriptor for "com/linkedin/history/api/protobuf/HistoryService.proto".
at com.google.protobuf.Descriptors$FileDescriptor.internalBuildGeneratedFileFrom(Descriptors.java:268)
at com.linkedin.history.api.protobuf.HistoryServiceProtos.(HistoryServiceProtos.java:1794)
Caused by: com.google.protobuf.Descriptors$DescriptorValidationException: com/linkedin/history/api/protobuf/HistoryService.proto: Dependencies passed to FileDescriptor.buildFrom() don't match those listed in the FileDescriptorProto.
at com.google.protobuf.Descriptors$FileDescriptor.buildFrom(Descriptors.java:221)
at com.google.protobuf.Descriptors$FileDescriptor.internalBuildGeneratedFileFrom(Descriptors.java:266)
I've read the post here but I think I'm doing everything correctly. Any suggestions on why I'm having the initializer errors? I'm compiling everything with the same -I flag.
I suspect that the problem is that when you're finding the proto file, you've given it the full path, e.g. proto/com/foo/api/Service.proto but when it refers to it via the include directory, it's using com/foo/api/Service.proto
Simple fix - run this from the proto directory:
find . -name *.proto -exec protoc --java_out=../java -I=. {} \;
I must admit I can't remember a lot of the details of protoc (which I really should) but I suspect that will work.
Another alternative which may work:
protoc --java_out=java `find . -name '*.proto'`
i.e. pass all the proto files into a single call to protoc.
I had the same error type in C# and here was my problem: I called the protoc in a pre-build step in my project. There I used Visual Studio built-in macros like $(SolutionDir) and $(ProjectDir) to retrieve necessary paths. Since I referenced *.proto files from other projects, I used two --proto_path options: one for the root path (to resolve import paths) and one for the file itself. My solution file was inside a subdirectory of the root directory, so I used the relative path .. to get to the root. Proto files are always in subdirectory gen of the particular project. All in all, the command was like this:
protoc.exe --proto_path=$(SolutionDir).. --proto_path=$(ProjectDir)gen $(ProjectDir)gen\DemoFile.proto
It compiled fine, but I got the System.TypeInitializationException at runtime on calling CreateBuilder() method. The problem was that both paths $(SolutionDir).. and $(ProjectDir) (though effectively pointing to the same directory) had different textual representation due to the relative path component ... I solved the problem by consistently using the same path like this:
protoc.exe --proto_path=$(SolutionDir).. $(SolutionDir)..\My\Demo\Project\Directory\gen\DemoFile.proto
It cost me almost 3 days to narrow down and recognize the problem, so I share my solution here in hope that it will save some time for someone.
Related
I have a moderately old, small Java application which has an option to read and export PDF files using the Apache PDFBox library (hereunder, "pdfbox-app.jar"). All the files, including this resource, are stored in a single flat folder.
This works fine when called from a JAR file:
D:\Prog\!GitHub\Arena>java -jar Athena.jar NPCGenerator -p
OED NPC Generator
-----------------
Writing Gwenllian-ElfFtr1Wiz1.pdf
It similarly works fine when run from my IDE (jGrasp).
But it fails when called from the command line, outside of its JAR:
D:\Prog\!GitHub\Arena>java NPCGenerator -p
OED NPC Generator
-----------------
Writing Eoin-HalflingFtr1.pdf
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/pdfbox/pdmodel/PDDoc
ument
at CharacterPDF.writePDF(CharacterPDF.java:49)
at NPCGenerator.printToPDF(NPCGenerator.java:294)
at NPCGenerator.makeAllNPCs(NPCGenerator.java:270)
at NPCGenerator.main(NPCGenerator.java:308)
Caused by: java.lang.ClassNotFoundException: org.apache.pdfbox.pdmodel.PDDocument
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.j
ava:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoader
s.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
... 4 more
What should I be doing to run this on the command line outside of its own JAR?
You should put the pdfbox jar, and any other dependencies, on the classpath:
java -classpath .;pdfbox-app.jar NPCGenerator -p
Without that, Java doesn't know where to look for org/apache/pdfbox classes. It looks for .class files relative to the default classpath (which is just ., the current directory), but does not look inside jars.
I am trying to generate C header file for JNI (Linux). I read documentation and questions on javah, but I still get the same error
Error: Could not find class file for 'org.sqlite.core.NativeDB'
I think I have very obvious mistake but I really don't see any... So, I need to generate header file from the NativeDB.class and the path is:
/u/users/maas/user123/sqlite/sqlite-jdbc-3.21.0/target/common-lib/org/sqlite/core/NativeDB.class
I go to the common-lib folder and call javah from the path of:
/u/users/maas/user123/sqlite/sqlite-jdbc-3.21.0/target/common-lib/
The commands I tried:
javah -classpath "/u/users/maas/user123/sqlite/sqlite-jdbc-3.21.0/target/common-lib/org/sqlite/core" org.sqlite.core.NativeDB
javah org.sqlite.core.NativeDB
The error I get:
Error: Could not find class file for 'org.sqlite.core.NativeDB'
I see the NativeDB.class file in the correct directory I mentioned. In the NativeDB.java (which is not in the same folder with NativeDB.class IF it is important) there is a package path:
package org.sqlite.core;
I found the issue (that was really obvious and dumb).
Commands I wrote in the question are correct. I am using USS (UNIX System Services) for Z/OS and ftp for transferring files. I didn't check that I sent .class files via ftp NOT in binary format. And for this reason Java couldn't find the classes because of wrong encoding.
All you need is just turn on the binary mode in the ftp like so:
ftp server.name.com
..login...
bi
mput *class
The bi command enables binary mode. The .class files are expected to be in this format.
I use JNA to load a c++ library (.so) in a java project. I package my library inside the jar, and load it from the jar when instantiating the java class that uses it. I do all this like so:
mvn install compiles the c++ code and packages the outcome dynamic library inside the jar.
I call in a static context when instantiating the LibraryWrapperClass the following
System.load( temp.getAbsolutePath() );
where temp is a temporary file containing the library which was found in the jar. This code is based on the work found here adamheinrich
- I call Native.loadLibrary(LIBRARYPATH) to wrap the library into a java class.
private interface Wrapper extends Library {
Wrapper INSTANCE = Native.loadLibrary( C_LIBRARY_PATH, Wrapper.class );
Pointer Constructor();
...
}
I run tests and validate that the library was found and up and running.
I use a java web project that depends on this project. It uses tomcat and runs fine in local.
My issue is that when I deploy on the server, the LibraryWrapperClass cannot instantiate. Error on server is:
java.lang.NoClassDefFoundError: Could not initialize class pacakgeName.LibraryWrapperClass
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:375)
at org.hibernate.annotations.common.util.StandardClassLoaderDelegateImpl.classForName(StandardClassLoaderDelegateImpl.java:57)
at org.hibernate.boot.internal.MetadataBuilderImpl$MetadataBuildingOptionsImpl$4.classForName(MetadataBuilderImpl.java:758)
at org.hibernate.annotations.common.reflection.java.JavaReflectionManager.classForName(JavaReflectionManager.java:144)
at...
This error seems that the library is found, since there is not the UnsatisfiedLinkError exception thrown. But something else is failing. Do someone know what could happen? How could I debug?
I recall that everything works perfectly in local.
How could I debug?
1. with strace
strace will give you what files Tomcat is trying to open : strace -f -e trace=file -o log.txt bin/startup.sh
After this, look for packageName in log.txt, or other files not found with :
egrep ' open.*No such file' log.txt
2. with JConsole
Enable JMX, launch a JConsole, go to VM summary tab, and check/compare very carefully VM arguments/classpath/library path/boot class path
3. dependency listing with ldd
If a dependency issue is likely to be the problem, the ldd sharedLibraryFile.so command lists all the dependencies and allows to track which one might be missing.
I have been trying to use a home grown test tool and after doing an update to Centos 6.4, I am no longer able to run the tcl based tool. I am getting the following error and I have no internet access on this server. Kindly advise how do I solve this problem?
Thanks
"XpUtils::iload -d /usr/local/testtool/repo/package/linux-glibc2.3-x86_64/lib/tcljava1.4.1 tclblend" failed:
couldn't load file "/usr/local/testtool/repo/package/linux-glibc2.3-x86_64/lib/tcljava1.4.1/libtclblend.so": libjava.so: cannot open shared object file: No such file or directory
while executing
"error "\"XpUtils::iload -d $dir tclblend\" failed:\n $errMsg""
(procedure "loadtclblend" line 168)
invoked from within
"loadtclblend /usr/local/testtool/repo/package/linux-glibc2.3-x86_64/lib/tcljava1.4.1"
("package ifneeded java 1.4.1" script)
invoked from within
"package require java"
("eval" body line 1)
invoked from within
"eval package require $pkg"
("foreach" body line 2)
invoked from within
"foreach pkg $pkgList {
set ::${pkg}Version [eval package require $pkg]
}"
(file "/usr/local/testtool/testtool" line 165)
If you read the error message trace, you'll see that it says that this is all caused by:
libjava.so: cannot open shared object file: No such file or directory
The first steps would then be to ensure that you've got a version of Java actually installed, to check that it includes the file libjava.so, and that the file has been indexed by the system shared library catalog.
It might also be worth checking that all its dependencies are also present and that you've got the architecture for the Tcl library and the Java library matched (e.g., both 32-bit) as those can cause odd failures when they go wrong.
I've to "compile" compass files dynamically in my java soft'. So, following explications found on stackoverflow, I've done these steps :
Get JRuby (1.7.3), configure PATH to jruby.jar and binaries (gem, rake ...) and learn to launch ruby script from Java
Get compass and dependancies gems into a local directory, using following command line
gem install -i ./compass compass
=> So I get a directory ./compass/ containing bin, cache,doc, gems & specifications directories.
Put gems in a jar using following command line (think to use a jar name which is not the same as the gems, to avoid JRuby "require" the jar instead of the gems)
jar cf compass-lib.jar -C compass .
Write a test script test.rb in local directory to test my jar. It contains :
require 'compass'
Compass.add_configuration(
{
:project_path => '.',
:sass_path => 'styles/scss',
:css_path => 'styles/css'
},
'custom' # A name for the configuration, can be anything you want
)
Compass.compiler.compile('test.scss', 'test.css')
Execute this script with JRuby, with following command line :
jruby -I . -rcompass-lib.jar test.rb
And get this error ...
Unable to load Sass. Please install it with one of the following commands:
gem install sass --pre
LoadError: no such file to load -- jar:file:C:/jruby-1.7.3/lib/jruby.jar!/gems/s
ass-3.2.8/lib/sass/../sass
require at org/jruby/RubyKernel.java:1027
require at c:/jruby-1.7.3/lib/ruby/shared/rubygems/custom_require.rb:36
(root) at jar:file:C:/jruby-1.7.3/lib/jruby.jar!/gems/sass-3.2.8/lib/sass/ver
sion.rb:5
require at org/jruby/RubyKernel.java:1027
(root) at c:/jruby-1.7.3/lib/ruby/shared/rubygems/custom_require.rb:1
require at c:/jruby-1.7.3/lib/ruby/shared/rubygems/custom_require.rb:36
require at org/jruby/RubyKernel.java:1027
(root) at jar:file:C:/jruby-1.7.3/lib/jruby.jar!/gems/sass-3.2.8/lib/sass.rb:
9
(root) at c:/jruby-1.7.3/lib/ruby/shared/rubygems/custom_require.rb:1
require at org/jruby/RubyKernel.java:1027
require at c:/jruby-1.7.3/lib/ruby/shared/rubygems/custom_require.rb:60
(root) at jar:file:C:/jruby-1.7.3/lib/jruby.jar!/gems/compass-0.12.2/lib/comp
ass/dependencies.rb:6
each at org/jruby/RubyArray.java:1613
(root) at c:/jruby-1.7.3/lib/ruby/shared/rubygems/custom_require.rb:1
require at org/jruby/RubyKernel.java:1027
require at c:/jruby-1.7.3/lib/ruby/shared/rubygems/custom_require.rb:36
(root) at test.rb:1
An idea of the problem and, maybe, of solution ? ;) Thanks by advance.
[UPDATE #1]
After Jörg W Mittag obvious suggestion, the error disapear. Thanks ;) Now, it just don't find the scss file, so it's a "normal problem" ;)
[UPDATE #2]
Having used compass with success in IRB, it's time to transpose the test through Java. So, I wrote some lines in Java to execute my ruby script, using only absolute path to avoid problems in a first time.
InputStream myFile = ISRessources.getFile("C:/Path/To/My/test.rb");
new ScriptingContainer().runScriptlet(myFile, "test.rb");
But ... how to "load" my compass-lib.jar ? What's the equivalent of the -r in JRuby ? I've tried to includ gems into jruby.jar, to add compass-lib.jar in externals jars in java build path, but both don't work, I still have :
LoadError: no such file to load -- compass
require at org/jruby/RubyKernel.java:1027
(root) at test.rb:1
Any idea ?
The error message says:
Unable to load Sass. Please install it with one of the following commands:
gem install sass --pre