I'm serializing a case class graph to JSON in an Android Scala app (using "com.hanhuy.sbt" % "android-sdk-plugin" % "1.3.5").
I'm using "org.json4s" %% "json4s-native" % "3.2.10", and it fails even with a simple case class which looks like this:
package test
case class Test(text: String)
The code to actually serialize looks like this:
import org.json4s._
import org.json4s.native.Serialization
import org.json4s.native.Serialization.{read, write}
// ...
implicit val formats = Serialization.formats(NoTypeHints)
val test = Test("test")
val serialized = write(test)
info(s"Serialized to '$serialized'")
The output is:
Serialized to '{}'
I suspect a ProGuard problem and my ProGuard settings in build.sbt are like this:
proguardScala in Android := true
proguardOptions in Android ++= Seq(
"-dontobfuscate",
"-dontoptimize",
"-keepattributes Signature",
"-dontwarn scala.collection.**", // required from Scala 2.11.3
"-dontwarn scala.collection.mutable.**", // required from Scala 2.11.0
"-ignorewarnings",
"-keep class scala.Dynamic",
"-keep class test.**"
)
I tried also with json4s-jackson but it made no difference.
The ProGuard log looks like this:
Warning: com.thoughtworks.paranamer.AnnotationParanamer$Jsr330Helper: can't find referenced class javax.inject.Named
Warning: com.thoughtworks.paranamer.AnnotationParanamer$Jsr330Helper: can't find referenced class javax.inject.Named
Warning: org.joda.convert.JDKStringConverter$9: can't find referenced class javax.xml.bind.DatatypeConverter
Warning: org.joda.convert.JDKStringConverter$9: can't find referenced class javax.xml.bind.DatatypeConverter
Warning: org.joda.convert.JDKStringConverter$9: can't find referenced class javax.xml.bind.DatatypeConverter
Note: com.google.android.gms.internal.av calls '(com.google.ads.mediation.MediationAdapter)Class.forName(variable).newInstance()'
Note: com.google.android.gms.maps.internal.q: can't find dynamically referenced class com.google.android.gms.maps.internal.CreatorImpl
Note: org.joda.time.DateTimeZone calls '(org.joda.time.tz.Provider)Class.forName(variable).newInstance()'
Note: org.joda.time.DateTimeZone calls '(org.joda.time.tz.NameProvider)Class.forName(variable).newInstance()'
Note: there were 1 unresolved dynamic references to classes or interfaces.
You should check if you need to specify additional program jars.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
Note: there were 3 class casts of dynamically created class instances.
You might consider explicitly keeping the mentioned classes and/or
their implementations (using '-keep').
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclasscast)
Warning: there were 5 unresolved references to classes or interfaces.
You may need to add missing library jars or update their versions.
If your code works fine without the missing classes, you can suppress
the warnings with '-dontwarn' options.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedclass)
Note: You're ignoring all warnings!
Any ideas?
You can create a JSONObject from a String using the constructor:
JSONObject json = new JSONObject(myString);
And to convert your JSONObject to a String, just use the toString() method:
String myString = json.toString();
Additionally, if you are trying to get a specific String value from the JSONObject, you can do this:
if (json.has("content"))
{
String content = json.getString("content");
//do something with content string
}
Finally, if you aren't very comfortable using JSONObject, I recommend using the tools provided by droidQuery to help you parse, such as:
Object[] array = $.toArray(myJSONArray);
and
Map<String, ?> map = $.map(myJSONObject);
Related
I developed a Android Binding Library to bind a printer Android AAR file (The AAR has its build action set to LibraryProjectZip), and the project is compiled using Android 7.1, using class-parse android class parser, and AndroidCodeGen Target: XAJavaInterop1. I can provide the simple Project in order to have full access to the code and library.
But I have the following error: 'The type or namespace 'ILibrary' does not exist in the namespace 'Com.Sun.Jna' at Com.Sun.Jna.Native.cs. So I decided to check at the Android library using a decompiler and here is what I found:
The AAR file contains an interface 'Library' (not ILibrary), and the Native.class file contains a method whose signature is the following and is the source of the error and which requires a Library object as input
public static Library synchronizeLibrary(final Library library){...}
The C# generated code contains a Com.Sun.Jna.ILibrary.cs file which contains a public abstract class 'Library':
[Register ("com/sun/jna/Library", DoNotGenerateAcw=true)] public abstract class Library : Java.Lang.Object {...}
but the generated Native.cs file has the counterpart method SynchronizeLibrary :
// Metadata.xml XPath method reference: [Register ("synchronizedLibrary", "(Lcom/sun/jna/Library;)Lcom/sun/jna/Library;", "")] public static unsafe global::Com.Sun.Jna.ILibrary SynchronizedLibrary(global::Com.Sun.Jna.ILibrary library) {...}
I do not understand why the C# generated method SynchronizedLibrary demands an ILibrary and not the Library.
I tried to modify the Metadata.xml file to rename the class Library to ILibrary but with no success. Moreover I have a warning saying that:
class-parse: warning: could not load .jar entry 'libjnidispatch.jnilib': System.Argument.OutOfRangeException,
I tried to change the name of the interface from Library to ILibrary using <attr path="/api/package[#name='com.sun.jna']/class[#name='Library']" name="managedName">ILibrary</attr> but the definition of the interface does not change. It is strange that I have a reference path for the members of the interface but not the interface itself
[Register ("com/sun/jna/Library", DoNotGenerateAcw=true)]
public abstract class Library : Java.Lang.Object {
internal Library ()
{
}
// Metadata.xml XPath field reference: path="/api/package[#name='com.sun.jna']/interface[#name='Library']/field[#name='OPTION_ALLOW_OBJECTS']"
[Register ("OPTION_ALLOW_OBJECTS")]
public const string OptionAllowObjects = (string) "allow-objects";,
and I do not know if it is related to the prior problem.
Thank you for any suggestion
Finally, I found the way to correct the error by modifying the name of the interfaces by adding the following lines to the Metadata file:
<attr path="/api/package[#name='com.sun.jna']/interface[#name='Library']" name="name">ILibrary</attr>
But now I have errors telling me that JNIENv does not contain method like NewString. And I am wondering if it is related to the warning i have telling me that It cannot load .jar entry libjnidispatch.jnilib
Any ideas, thanks
I am creating Annotation processor with annotation that takes class names, check if the name is CamelCase and writes all the classes which don't use camelcase.
This is the function which writes all those classes:
private fun checkCamelVariable(classElement: TypeElement) {
classElement.enclosedElements.filter {
!it.simpleName.toString().isDefinedCamelCase()
}.forEach {
printWarning("Detected non-camelcase name: ${it.simpleName}.")
}
}
In my build log i get:
warning: Detected non-camelcase name: TAG.[WARN] Incremental annotation processing requested, but support is disabled because the following processors are not incremental: com.example.processor.GenerateProcessor (NON_INCREMENTAL), com.google.auto.service.processor.AutoServiceProcessor (NON_INCREMENTAL).
Which means my annotation is working but I can not get the class names.
Looked on places like this: How to get rid of Incremental annotation processing requested warning?
but none of suggestions helped me.
Please Excuse my absolute lack of Android JNI
I want to analize/call one function hidden in shared object: libEncodeAndDecodeUtils.so
orginal code uses it like this:
package com.midea.msmartsdk.common.utils;
public class EncodeAndDecodeUtils {
public native String esha(String str, String str2, String str3);
}
Ida decompiler shows:
Java_com_midea_msmartsdk_common_utils_EncodeAndDecodeUtils_esha
How can I call this function in my project?
My current attempt:
new AndroidStudio project with JNI support
adding folder \src\main\jniLibs\armeabi-v7a
copy libEncodeAndDecodeUtils.so to armeabi-v7a
buid.bradle android{ defaultConfig { ndk {abiFilters "armeabi-v7a"} }
and creating class
package com.midea.msmartsdk.common.utils.so_test4;
public class EncodeAndDecodeUtils {
static {
System.loadLibrary("EncodeAndDecodeUtils");
}
public native String esha(String str, String str2, String str3);
}
this lead me to error:
E/zygote: No implementation found for
java.lang.String com.midea.msmartsdk.common.utils.so_test4.EncodeAndDecodeUtils.esha
(java.lang.String,
java.lang.String,
java.lang.String)
(tried
Java_com_midea_msmartsdk_common_utils_so_1test4_EncodeAndDecodeUtils_esha
and Java_com_midea_msmartsdk_common_utils_so_1test4_EncodeAndDecodeUtils_esha__Ljava_lang_String_2Ljava_lang_String_2Ljava_lang_String_2)
is this my problem?
Java_com_midea_msmartsdk_common_utils_EncodeAndDecodeUtils_esha
!=
Java_com_midea_msmartsdk_common_utils_so_1test4_EncodeAndDecodeUtils_esha
If you try to access esha from your own code, then you HAVE TO declare this method exactly the same as its original form, because JNI will try to find the implementation following some fixed convention. According to https://docs.oracle.com/javase/1.5.0/docs/guide/jni/spec/design.html
Resolving Native Method Names
Dynamic linkers resolve entries based on their names. A native method name is concatenated from the following components:
the prefix Java_
a mangled fully-qualified class name
an underscore (“_”) separator
a mangled method name for overloaded native methods,
two underscores (“__”) followed by the mangled argument signature
Simply speaking, it will be something like Java_packagename_ClassName_methodsignature.
For example, in your case, it is Java_com_midea_msmartsdk_common_utils_EncodeAndDecodeUtils_esha.
So, try to remove so_test4 from your package name.
I have an android wear 2.0 project with the following dependency:
compile 'com.google.android.gms:play-services-wearable:11.0.4'
The play-services-wearable dependency results in an inherited dependency on play-services-basement, which contains classes such as com.google.protobuf.zzc that contain reflective code e.g:
final class zzc {
private static Class<?> zzcrO = zzLq();
private static Class<?> zzLq() {
try {
return Class.forName("com.google.protobuf.ExtensionRegistry");
} catch (ClassNotFoundException var0) {
return null;
}
}
This dependency therefore results in the following proguard Notes:
Note: com.google.protobuf.zzc: can't find dynamically referenced class com.google.protobuf.ExtensionRegistry
Note: com.google.protobuf.zzd: can't find dynamically referenced class com.google.protobuf.Extension
Note: com.google.protobuf.zze: can't find dynamically referenced class libcore.io.Memory
Note: com.google.protobuf.zze: can't find dynamically referenced class org.robolectric.Robolectric
Note: there were 4 unresolved dynamic references to classes or interfaces.
You should check if you need to specify additional program jars.
(http://proguard.sourceforge.net/manual/troubleshooting.html#dynamicalclass)
So my questions are:
Do I need to include an additional dependency to prevent the ProGuard from displaying the above notes?
If so, why doesn't play-services-basement include the required transitive dependencies (i.e. protobuf) automatically?
Would it be safe to add '-dontnote' rules to my proguard files to hide the above warnings? I'm concerned that since this code is reflective, there's a chance that it may actually be used by google play services and cause a Runtime exception if I just ignore the problem.
I have an Android Scala app that uses SBT + ProGuard for building.
In a library project I have this:
package es.fcc.bibl.bd.sincr
class Columna[T] { ... }
class TablaBase {
lazy val columnas: List[Columna[_]] = ....
}
trait Soporte {
this: TablaBase =>
def fabricaSoporte(w: Writer, cols: List[Columna[_]] = columnas) {
}
in my app code, I have this:
package es.fcc.incidencias.bd
object sgiein extends TablaBase with Soporte { .... }
and when building my project, I get these cryptic errors:
Warning: es.fcc.incidencias.bd.sgiein: can't find referenced method 'void es$fcc$bibl$bd$sincr$TablaBaseSincronizada$_setter_$cols_$eq(scala.collection.immutable.List)' in program class es.fcc.incidencias.bd.sgiein$
Warning: es.fcc.incidencias.bd.sgiein: can't find referenced method 'scala.collection.immutable.List cols()' in program class es.fcc.incidencias.bd.sgiein$
Your input classes appear to be inconsistent.
You may need to recompile the code.
(http://proguard.sourceforge.net/manual/troubleshooting.html#unresolvedprogramclassmember)
The problem is related with the default value of the argument cols.
If I remove that argument, everything builds ok.
I've tried to change the ProGuard options to these with no luck:
-keepclassmembers class es.fcc.bibl.bd.sincr.TablaBaseSincronizada* {
** *(**);
}
-keepclassmembers class es.fcc.incidencias.bd.* {
** *(**);
}
I don't understand why I'm having this problem.
I've come to the conclusion that these errors can be safely ignored.
It must be some internal error in ProGuard.
Use the -dontwarn directive in the ProGuard configuration for that purpose.