Package: libsnappy-java Version: 1.0.4.1~dfsg-1 Severity: grave Tags: patch Justification: renders package unusable
Dear Maintainer, Apologies if this the wrong package to open a bug against, I was unsure whether I should open it against libsnappy-java or libsnappy1, feel free to reassign it if needed While trying to use the simple example from the snappy-java documentation attached below I encountered an error of FAILED_LOAD_NATIVE_LIBRARY. After a lot of reading it seems like the upstream ships compiled versions of shared object (.so) files for various OSes and architectures that get included in the shipped jar file. Those are stripped out in the Debian package and a dependency to the libsnappy1 package is declared. That is a nice approach IMHO However, the .so file shipped by the libsnappy1 package (/usr/lib/libsnappy.so.1.1.3) does not contain the necessary JNI bindings and as a result the JNI calls from the Java code fail. I have managed to bypass the problem by recompiling the libsnappy1 package with the JNI bindings provided in the libsnappy-java package. I attach the patch. I am not sure however if this is the best possible solution. It is however a relatively clean one. Of course this solution is against the libsnappy1 package and not the libsnappy-java package Reproduce with: SnappyTests.java: import org.xerial.snappy.Snappy; import java.lang.String; import java.lang.System; import java.io.IOException; import java.io.UnsupportedEncodingException; class SnappyTests { public static void main(String[] args) throws UnsupportedEncodingException, IOException { String input = "Hello snappy-java! Snappy-java is a JNI-based wrapper of " + "Snappy, a fast compresser/decompresser."; byte[] compressed = Snappy.compress(input.getBytes("UTF-8")); byte[] uncompressed = Snappy.uncompress(compressed); String result = new String(uncompressed, "UTF-8"); System.out.println(result); } } Compile with: javac -cp /usr/share/java/snappy-java.jar SnappyTests.java Run with: java -cp '/usr/share/java/snappy-java.jar:.' SnappyTests Stacktrace returned is: java.lang.reflect.InvocationTargetException at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:601) at org.xerial.snappy.SnappyLoader.loadNativeLibrary(SnappyLoader.java:317) at org.xerial.snappy.SnappyLoader.load(SnappyLoader.java:219) at org.xerial.snappy.Snappy.<clinit>(Snappy.java:44) at SnappyTests.main(SnappyTests.java:11) Caused by: java.lang.UnsatisfiedLinkError: no snappyjava in java.library.path at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1856) at java.lang.Runtime.loadLibrary0(Runtime.java:845) at java.lang.System.loadLibrary(System.java:1084) at org.xerial.snappy.SnappyNativeLoader.loadLibrary(SnappyNativeLoader.java:52) ... 8 more Exception in thread "main" org.xerial.snappy.SnappyError: [FAILED_TO_LOAD_NATIVE_LIBRARY] null at org.xerial.snappy.SnappyLoader.load(SnappyLoader.java:229) at org.xerial.snappy.Snappy.<clinit>(Snappy.java:44) at SnappyTests.main(SnappyTests.java:11) -- System Information: Debian Release: 7.3 APT prefers stable-updates APT policy: (500, 'stable-updates'), (500, 'stable') Architecture: amd64 (x86_64) Kernel: Linux 3.11-0.bpo.2-amd64 (SMP w/4 CPU cores) Locale: LANG=en_US.utf8, LC_CTYPE=en_US.utf8 (charmap=UTF-8) Shell: /bin/sh linked to /bin/dash
diff -urN b/snappy-1.0.4/debian/libsnappy1.links a/snappy-1.0.4/debian/libsnappy1.links --- b/snappy-1.0.4/debian/libsnappy1.links 1970-01-01 00:00:00.000000000 +0000 +++ a/snappy-1.0.4/debian/libsnappy1.links 2013-11-06 14:47:02.701611660 +0000 @@ -0,0 +1 @@ +usr/lib/libsnappy.so.1 usr/lib/libsnappyjava.so diff -urN b/snappy-1.0.4/debian/patches/jni.patch a/snappy-1.0.4/debian/patches/jni.patch --- b/snappy-1.0.4/debian/patches/jni.patch 1970-01-01 00:00:00.000000000 +0000 +++ a/snappy-1.0.4/debian/patches/jni.patch 2013-11-06 14:39:55.093530261 +0000 @@ -0,0 +1,411 @@ +--- /dev/null 2013-05-23 22:06:22.347926853 +0000 ++++ b/SnappyNative.cc 2013-11-06 12:27:53.491596706 +0000 +@@ -0,0 +1,237 @@ ++/*-------------------------------------------------------------------------- ++ * Copyright 2011 Taro L. Saito ++ * ++ * Licensed under the Apache License, Version 2.0 (the "License"); ++ * you may not use this file except in compliance with the License. ++ * You may obtain a copy of the License at ++ * ++ * http://www.apache.org/licenses/LICENSE-2.0 ++ * ++ * Unless required by applicable law or agreed to in writing, software ++ * distributed under the License is distributed on an "AS IS" BASIS, ++ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++ * See the License for the specific language governing permissions and ++ * limitations under the License. ++ *--------------------------------------------------------------------------*/ ++#include <string> ++#include <cstring> ++#include <snappy.h> ++#include "SnappyNative.h" ++ ++void throw_exception(JNIEnv *env, jobject self, int errorCode) ++{ ++ jclass c = env->FindClass("Lorg/xerial/snappy/SnappyNative;"); ++ if(c==0) ++ return; ++ jmethodID mth_throwex = env->GetMethodID(c, "throw_error", "(I)V"); ++ if(mth_throwex == 0) ++ return; ++ env->CallVoidMethod(self, mth_throwex, (jint) errorCode); ++} ++ ++ ++JNIEXPORT jstring JNICALL Java_org_xerial_snappy_SnappyNative_nativeLibraryVersion ++ (JNIEnv * env, jobject self) ++{ ++ return env->NewStringUTF("1.0.4"); ++} ++ ++/* ++ * Class: org_xerial_snappy_Snappy ++ * Method: compress ++ * Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)J ++ */ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress__Ljava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2I ++ (JNIEnv* env, jobject self, jobject uncompressed, jint upos, jint ulen, jobject compressed, jint cpos) ++{ ++ char* uncompressedBuffer = (char*) env->GetDirectBufferAddress(uncompressed); ++ char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed); ++ if(uncompressedBuffer == 0 || compressedBuffer == 0) { ++ throw_exception(env, self, 3); ++ return (jint) 0; ++ } ++ ++ size_t compressedLength; ++ snappy::RawCompress(uncompressedBuffer + upos, (size_t) ulen, compressedBuffer + cpos, &compressedLength); ++ return (jint) compressedLength; ++} ++ ++ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress__Ljava_lang_Object_2IILjava_lang_Object_2I ++ (JNIEnv * env, jobject self, jobject input, jint inputOffset, jint inputLen, jobject output, jint outputOffset) ++{ ++ char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0); ++ char* out = (char*) env->GetPrimitiveArrayCritical((jarray) output, 0); ++ if(in == 0 || out == 0) { ++ // out of memory ++ throw_exception(env, self, 4); ++ return 0; ++ } ++ ++ size_t compressedLength; ++ snappy::RawCompress(in + inputOffset, (size_t) inputLen, out + outputOffset, &compressedLength); ++ ++ env->ReleasePrimitiveArrayCritical((jarray) input, in, 0); ++ env->ReleasePrimitiveArrayCritical((jarray) output, out, 0); ++ ++ return (jint) compressedLength; ++} ++ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompress__Ljava_lang_Object_2IILjava_lang_Object_2I ++(JNIEnv * env, jobject self, jobject input, jint inputOffset, jint inputLength, jobject output, jint outputOffset) ++{ ++ char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0); ++ char* out = (char*) env->GetPrimitiveArrayCritical((jarray) output, 0); ++ if(in == 0 || out == 0) { ++ // out of memory ++ throw_exception(env, self, 4); ++ return 0; ++ } ++ ++ size_t uncompressedLength; ++ snappy::GetUncompressedLength(in + inputOffset, (size_t) inputLength, &uncompressedLength); ++ bool ret = snappy::RawUncompress(in + inputOffset, (size_t) inputLength, out + outputOffset); ++ ++ env->ReleasePrimitiveArrayCritical((jarray) input, in, 0); ++ env->ReleasePrimitiveArrayCritical((jarray) output, out, 0); ++ ++ if(!ret) { ++ throw_exception(env, self, 5); ++ return 0; ++ } ++ ++ return (jint) uncompressedLength; ++} ++ ++ ++/* ++ * Class: org_xerial_snappy_Snappy ++ * Method: uncompress ++ * Signature: (Ljava/nio/ByteBuffer;Ljava/nio/ByteBuffer;)Z ++ */ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompress__Ljava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2I ++ (JNIEnv * env, jobject self, jobject compressed, jint cpos, jint clen, jobject decompressed, jint dpos) ++{ ++ char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed); ++ char* decompressedBuffer = (char*) env->GetDirectBufferAddress(decompressed); ++ if(compressedBuffer == 0 || decompressedBuffer == 0) { ++ throw_exception(env, self, 3); ++ return (jint) 0; ++ } ++ ++ size_t decompressedLength; ++ snappy::GetUncompressedLength(compressedBuffer + cpos, (size_t) clen, &decompressedLength); ++ bool ret = snappy::RawUncompress(compressedBuffer + cpos, (size_t) clen, decompressedBuffer + dpos); ++ if(!ret) { ++ throw_exception(env, self, 5); ++ return 0; ++ } ++ ++ return (jint) decompressedLength; ++} ++ ++ ++ ++/* ++ * Class: org_xerial_snappy_Snappy ++ * Method: maxCompressedLength ++ * Signature: (J)J ++ */ ++ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_maxCompressedLength ++ (JNIEnv *, jobject, jint size) ++{ ++ size_t l = snappy::MaxCompressedLength((size_t) size); ++ return (jint) l; ++} ++ ++/* ++ * Class: org_xerial_snappy_Snappy ++ * Method: getUncompressedLength ++ * Signature: (Ljava/nio/ByteBuffer;)J ++ */ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength__Ljava_nio_ByteBuffer_2II ++ (JNIEnv * env, jobject self, jobject compressed, jint cpos, jint clen) ++{ ++ char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed); ++ if(compressedBuffer == 0) { ++ throw_exception(env, self, 3); ++ return (jint) 0; ++ } ++ ++ size_t result; ++ bool ret = snappy::GetUncompressedLength(compressedBuffer + cpos, (size_t) clen, &result); ++ if(!ret) { ++ throw_exception(env, self, 2); ++ return 0; ++ } ++ return (jint) result; ++} ++ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength__Ljava_lang_Object_2II ++ (JNIEnv * env, jobject self, jobject input, jint offset, jint length) ++{ ++ char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0); ++ if(in == 0) { ++ // out of memory ++ throw_exception(env, self, 4); ++ return 0; ++ } ++ ++ size_t result; ++ bool ret = snappy::GetUncompressedLength(in + offset, (size_t) length, &result); ++ env->ReleasePrimitiveArrayCritical((jarray) input, in, 0); ++ ++ if(!ret) { ++ throw_exception(env, self, 2); ++ return 0; ++ } ++ ++ return (jint) result; ++} ++ ++JNIEXPORT jboolean JNICALL Java_org_xerial_snappy_SnappyNative_isValidCompressedBuffer__Ljava_nio_ByteBuffer_2II ++ (JNIEnv * env, jobject self, jobject compressed, jint cpos, jint clen) ++{ ++ char* compressedBuffer = (char*) env->GetDirectBufferAddress(compressed); ++ if(compressedBuffer == 0) { ++ throw_exception(env, self, 3); ++ return (jint) 0; ++ } ++ bool ret = snappy::IsValidCompressedBuffer(compressedBuffer + cpos, (size_t) clen); ++ return ret; ++} ++ ++ ++JNIEXPORT jboolean JNICALL Java_org_xerial_snappy_SnappyNative_isValidCompressedBuffer__Ljava_lang_Object_2II ++ (JNIEnv * env, jobject self, jobject input, jint offset, jint length) ++{ ++ char* in = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0); ++ if(in == 0) { ++ // out of memory ++ throw_exception(env, self, 4); ++ return 0; ++ } ++ bool ret = snappy::IsValidCompressedBuffer(in + offset, (size_t) length); ++ env->ReleasePrimitiveArrayCritical((jarray) input, in, 0); ++ return ret; ++} ++ ++JNIEXPORT void JNICALL Java_org_xerial_snappy_SnappyNative_arrayCopy ++ (JNIEnv * env, jobject self, jobject input, jint offset, jint length, jobject output, jint output_offset) ++{ ++ char* src = (char*) env->GetPrimitiveArrayCritical((jarray) input, 0); ++ char* dest = (char*) env->GetPrimitiveArrayCritical((jarray) output, 0); ++ if(src == 0 || dest == 0) { ++ // out of memory ++ throw_exception(env, self, 4); ++ return; ++ } ++ ++ memcpy(dest+output_offset, src+offset, (size_t) length); ++ ++ env->ReleasePrimitiveArrayCritical((jarray) input, src, 0); ++ env->ReleasePrimitiveArrayCritical((jarray) output, dest, 0); ++} ++ ++ +--- /dev/null 2013-05-23 22:06:22.347926853 +0000 ++++ b/jni_md.h 2013-11-06 12:28:49.066580304 +0000 +@@ -0,0 +1,24 @@ ++/* ++ * %W% %E% ++ * ++ * Copyright (c) 2006, Oracle and/or its affiliates. All rights reserved. ++ * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. ++ */ ++ ++#ifndef _JAVASOFT_JNI_MD_H_ ++#define _JAVASOFT_JNI_MD_H_ ++ ++#define JNIEXPORT __attribute__((__visibility__("default"))) ++#define JNIIMPORT ++#define JNICALL ++ ++typedef int jint; ++#ifdef _LP64 /* 64-bit Solaris */ ++typedef long jlong; ++#else ++typedef long long jlong; ++#endif ++ ++typedef signed char jbyte; ++ ++#endif /* !_JAVASOFT_JNI_MD_H_ */ +--- /dev/null 2013-05-23 22:06:22.347926853 +0000 ++++ b/SnappyNative.h 2013-11-06 12:27:55.443561022 +0000 +@@ -0,0 +1,101 @@ ++/* DO NOT EDIT THIS FILE - it is machine generated */ ++#include <jni.h> ++/* Header for class org_xerial_snappy_SnappyNative */ ++ ++#ifndef _Included_org_xerial_snappy_SnappyNative ++#define _Included_org_xerial_snappy_SnappyNative ++#ifdef __cplusplus ++extern "C" { ++#endif ++/* ++ * Class: org_xerial_snappy_SnappyNative ++ * Method: nativeLibraryVersion ++ * Signature: ()Ljava/lang/String; ++ */ ++JNIEXPORT jstring JNICALL Java_org_xerial_snappy_SnappyNative_nativeLibraryVersion ++ (JNIEnv *, jobject); ++ ++/* ++ * Class: org_xerial_snappy_SnappyNative ++ * Method: rawCompress ++ * Signature: (Ljava/nio/ByteBuffer;IILjava/nio/ByteBuffer;I)I ++ */ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress__Ljava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2I ++ (JNIEnv *, jobject, jobject, jint, jint, jobject, jint); ++ ++/* ++ * Class: org_xerial_snappy_SnappyNative ++ * Method: rawCompress ++ * Signature: (Ljava/lang/Object;IILjava/lang/Object;I)I ++ */ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawCompress__Ljava_lang_Object_2IILjava_lang_Object_2I ++ (JNIEnv *, jobject, jobject, jint, jint, jobject, jint); ++ ++/* ++ * Class: org_xerial_snappy_SnappyNative ++ * Method: rawUncompress ++ * Signature: (Ljava/nio/ByteBuffer;IILjava/nio/ByteBuffer;I)I ++ */ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompress__Ljava_nio_ByteBuffer_2IILjava_nio_ByteBuffer_2I ++ (JNIEnv *, jobject, jobject, jint, jint, jobject, jint); ++ ++/* ++ * Class: org_xerial_snappy_SnappyNative ++ * Method: rawUncompress ++ * Signature: (Ljava/lang/Object;IILjava/lang/Object;I)I ++ */ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_rawUncompress__Ljava_lang_Object_2IILjava_lang_Object_2I ++ (JNIEnv *, jobject, jobject, jint, jint, jobject, jint); ++ ++/* ++ * Class: org_xerial_snappy_SnappyNative ++ * Method: maxCompressedLength ++ * Signature: (I)I ++ */ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_maxCompressedLength ++ (JNIEnv *, jobject, jint); ++ ++/* ++ * Class: org_xerial_snappy_SnappyNative ++ * Method: uncompressedLength ++ * Signature: (Ljava/nio/ByteBuffer;II)I ++ */ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength__Ljava_nio_ByteBuffer_2II ++ (JNIEnv *, jobject, jobject, jint, jint); ++ ++/* ++ * Class: org_xerial_snappy_SnappyNative ++ * Method: uncompressedLength ++ * Signature: (Ljava/lang/Object;II)I ++ */ ++JNIEXPORT jint JNICALL Java_org_xerial_snappy_SnappyNative_uncompressedLength__Ljava_lang_Object_2II ++ (JNIEnv *, jobject, jobject, jint, jint); ++ ++/* ++ * Class: org_xerial_snappy_SnappyNative ++ * Method: isValidCompressedBuffer ++ * Signature: (Ljava/nio/ByteBuffer;II)Z ++ */ ++JNIEXPORT jboolean JNICALL Java_org_xerial_snappy_SnappyNative_isValidCompressedBuffer__Ljava_nio_ByteBuffer_2II ++ (JNIEnv *, jobject, jobject, jint, jint); ++ ++/* ++ * Class: org_xerial_snappy_SnappyNative ++ * Method: isValidCompressedBuffer ++ * Signature: (Ljava/lang/Object;II)Z ++ */ ++JNIEXPORT jboolean JNICALL Java_org_xerial_snappy_SnappyNative_isValidCompressedBuffer__Ljava_lang_Object_2II ++ (JNIEnv *, jobject, jobject, jint, jint); ++ ++/* ++ * Class: org_xerial_snappy_SnappyNative ++ * Method: arrayCopy ++ * Signature: (Ljava/lang/Object;IILjava/lang/Object;I)V ++ */ ++JNIEXPORT void JNICALL Java_org_xerial_snappy_SnappyNative_arrayCopy ++ (JNIEnv *, jobject, jobject, jint, jint, jobject, jint); ++ ++#ifdef __cplusplus ++} ++#endif ++#endif +--- a/Makefile.in 2011-09-15 19:29:19.000000000 +0000 ++++ b/Makefile.in 2013-11-06 13:06:29.671764323 +0000 +@@ -83,7 +83,7 @@ + LTLIBRARIES = $(lib_LTLIBRARIES) + libsnappy_la_LIBADD = + am_libsnappy_la_OBJECTS = snappy.lo snappy-sinksource.lo \ +- snappy-stubs-internal.lo snappy-c.lo ++ snappy-stubs-internal.lo snappy-c.lo SnappyNative.lo + libsnappy_la_OBJECTS = $(am_libsnappy_la_OBJECTS) + libsnappy_la_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ +@@ -100,7 +100,7 @@ + snappy_unittest_LINK = $(LIBTOOL) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(snappy_unittest_LDFLAGS) $(LDFLAGS) -o $@ +-DEFAULT_INCLUDES = -I.@am__isrc@ ++DEFAULT_INCLUDES = -I.@am__isrc@ -I/usr/lib/jvm/java-6-openjdk-amd64/include + depcomp = $(SHELL) $(top_srcdir)/depcomp + am__depfiles_maybe = depfiles + am__mv = mv -f +@@ -270,9 +270,9 @@ + + # Library. + lib_LTLIBRARIES = libsnappy.la +-libsnappy_la_SOURCES = snappy.cc snappy-sinksource.cc snappy-stubs-internal.cc snappy-c.cc ++libsnappy_la_SOURCES = snappy.cc snappy-sinksource.cc snappy-stubs-internal.cc snappy-c.cc SnappyNative.cc + libsnappy_la_LDFLAGS = -version-info $(SNAPPY_LTVERSION) +-include_HEADERS = snappy.h snappy-sinksource.h snappy-stubs-public.h snappy-c.h ++include_HEADERS = snappy.h snappy-sinksource.h snappy-stubs-public.h snappy-c.h SnappyNative.h jni_md.h + noinst_HEADERS = snappy-internal.h snappy-stubs-internal.h snappy-test.h + + # Unit tests and benchmarks. +@@ -392,6 +392,7 @@ + distclean-compile: + -rm -f *.tab.c + ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/SnappyNative.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snappy-c.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snappy-sinksource.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/snappy-stubs-internal.Plo@am__quote@ diff -urN b/snappy-1.0.4/debian/patches/series a/snappy-1.0.4/debian/patches/series --- b/snappy-1.0.4/debian/patches/series 1970-01-01 00:00:00.000000000 +0000 +++ a/snappy-1.0.4/debian/patches/series 2013-11-06 14:40:02.957532121 +0000 @@ -0,0 +1 @@ +jni.patch diff -urN b/snappy-1.0.4/debian/source/format a/snappy-1.0.4/debian/source/format --- b/snappy-1.0.4/debian/source/format 1970-01-01 00:00:00.000000000 +0000 +++ a/snappy-1.0.4/debian/source/format 2013-11-06 14:39:41.045526935 +0000 @@ -0,0 +1 @@ +3.0 (quilt)