使用 proguard 进行混淆后,使用 google guice 进行注入不再起作用
有没有人尝试过将 google guice 的使用与混淆(特别是 proguard)结合起来? 我的代码的混淆版本不适用于 google guice,因为 guice 抱怨缺少类型参数。即使相关类被排除在混淆之外,这些信息似乎也会被 proguard 所做的转换步骤删除。
堆栈跟踪看起来像这样:
com.google.inject.CreationException: Guice creation errors:
1) Cannot inject a Provider that has no type parameter
while locating com.google.inject.Provider
for parameter 0 at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setPasswordPanelProvider(SourceFile:499)
at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setPasswordPanelProvider(SourceFile:499)
while locating de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel
for parameter 0 at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65)
at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65)
at de.repower.lvs.client.admin.user.administration.o.a(SourceFile:38)
2) Cannot inject a Provider that has no type parameter
while locating com.google.inject.Provider
for parameter 0 at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setWindTurbineAccessGroupProvider(SourceFile:509)
at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setWindTurbineAccessGroupProvider(SourceFile:509)
while locating de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel
for parameter 0 at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65)
at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65)
at de.repower.lvs.client.admin.user.administration.o.a(SourceFile:38)
2 errors
at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:354)
at com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:152)
at com.google.inject.InjectorBuilder.build(InjectorBuilder.java:105)
at com.google.inject.Guice.createInjector(Guice.java:92)
at com.google.inject.Guice.createInjector(Guice.java:69)
at com.google.inject.Guice.createInjector(Guice.java:59)
我尝试创建一个小示例(不使用 guice),它似乎重现了问题:
package de.repower.common;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
class SomeClass<S> {
}
public class ParameterizedTypeTest {
public void someMethod(SomeClass<Integer> param) {
System.out.println("value: " + param);
System.setProperty("my.dummmy.property", "hallo");
}
private static void checkParameterizedMethod(ParameterizedTypeTest testObject) {
System.out.println("checking parameterized method ...");
Method[] methods = testObject.getClass().getMethods();
for (Method method : methods) {
if (method.getName().equals("someMethod")) {
System.out.println("Found method " + method.getName());
Type[] types = method.getGenericParameterTypes();
Type parameterType = types[0];
if (parameterType instanceof ParameterizedType) {
Type parameterizedType = ((ParameterizedType) parameterType).getActualTypeArguments()[0];
System.out.println("Parameter: " + parameterizedType);
System.out.println("Class: " + ((Class) parameterizedType).getName());
} else {
System.out.println("Failed: type ist not instance of ParameterizedType");
}
}
}
}
public static void main(String[] args) {
System.out.println("Starting ...");
try {
ParameterizedTypeTest someInstance = new ParameterizedTypeTest();
checkParameterizedMethod(someInstance);
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
如果您运行此代码 unsbfuscated,输出看起来像这样:
Starting ...
checking parameterized method ...
Found method someMethod
Parameter: class java.lang.Integer
Class: java.lang.Integer
但是运行使用 proguard 混淆的版本会产生:
Starting ...
checking parameterized method ...
Found method someMethod
Failed: type ist not instance of ParameterizedType
这些是我用于混淆的选项:
-injars classes_eclipse\methodTest.jar
-outjars classes_eclipse\methodTestObfuscated.jar
-libraryjars 'C:\Program Files\Java\jre6\lib\rt.jar'
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontshrink
-printusage classes_eclipse\shrink.txt
-dontoptimize
-dontpreverify
-verbose
-keep class **.ParameterizedTypeTest.class {
<fields>;
<methods>;
}
-keep class ** {
<fields>;
<methods>;
}
# Keep - Applications. Keep all application classes, along with their 'main'
# methods.
-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}
# Also keep - Enumerations. Keep the special static methods that are required in
# enumeration classes.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Also keep - Database drivers. Keep all implementations of java.sql.Driver.
-keep class * extends java.sql.Driver
# Also keep - Swing UI L&F. Keep all extensions of javax.swing.plaf.ComponentUI,
# along with the special 'createUI' method.
-keep class * extends javax.swing.plaf.ComponentUI {
public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent);
}
# Keep names - Native method names. Keep all native class/method names.
-keepclasseswithmembers,allowshrinking class * {
native <methods>;
}
# Keep names - _class method names. Keep all .class method names. This may be
# useful for libraries that will be obfuscated again with different obfuscators.
-keepclassmembers,allowshrinking class * {
java.lang.Class class$(java.lang.String);
java.lang.Class class$(java.lang.String,boolean);
}
有谁知道如何解决这个问题(除了将相关文件放入单独的 jar 中而不对其进行混淆的明显解决方法之外)?
谨致问候,
斯特凡
Has anyone ever tried to combine the use of google guice with obfuscation (in particular proguard)?
The obfuscated version of my code does not work with google guice as guice complains about missing type parameters. This information seems to be erased by the transformation step that proguard does, even when the relevant classes are excluded from the obfuscation.
The stack trace looks like this:
com.google.inject.CreationException: Guice creation errors:
1) Cannot inject a Provider that has no type parameter
while locating com.google.inject.Provider
for parameter 0 at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setPasswordPanelProvider(SourceFile:499)
at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setPasswordPanelProvider(SourceFile:499)
while locating de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel
for parameter 0 at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65)
at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65)
at de.repower.lvs.client.admin.user.administration.o.a(SourceFile:38)
2) Cannot inject a Provider that has no type parameter
while locating com.google.inject.Provider
for parameter 0 at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setWindTurbineAccessGroupProvider(SourceFile:509)
at de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel.setWindTurbineAccessGroupProvider(SourceFile:509)
while locating de.repower.lvs.client.admin.user.administration.AdminUserCommonPanel
for parameter 0 at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65)
at de.repower.lvs.client.admin.user.administration.b.k.setParentPanel(SourceFile:65)
at de.repower.lvs.client.admin.user.administration.o.a(SourceFile:38)
2 errors
at com.google.inject.internal.Errors.throwCreationExceptionIfErrorsExist(Errors.java:354)
at com.google.inject.InjectorBuilder.initializeStatically(InjectorBuilder.java:152)
at com.google.inject.InjectorBuilder.build(InjectorBuilder.java:105)
at com.google.inject.Guice.createInjector(Guice.java:92)
at com.google.inject.Guice.createInjector(Guice.java:69)
at com.google.inject.Guice.createInjector(Guice.java:59)
I tried to create a small example (without using guice) that seems to reproduce the problem:
package de.repower.common;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
class SomeClass<S> {
}
public class ParameterizedTypeTest {
public void someMethod(SomeClass<Integer> param) {
System.out.println("value: " + param);
System.setProperty("my.dummmy.property", "hallo");
}
private static void checkParameterizedMethod(ParameterizedTypeTest testObject) {
System.out.println("checking parameterized method ...");
Method[] methods = testObject.getClass().getMethods();
for (Method method : methods) {
if (method.getName().equals("someMethod")) {
System.out.println("Found method " + method.getName());
Type[] types = method.getGenericParameterTypes();
Type parameterType = types[0];
if (parameterType instanceof ParameterizedType) {
Type parameterizedType = ((ParameterizedType) parameterType).getActualTypeArguments()[0];
System.out.println("Parameter: " + parameterizedType);
System.out.println("Class: " + ((Class) parameterizedType).getName());
} else {
System.out.println("Failed: type ist not instance of ParameterizedType");
}
}
}
}
public static void main(String[] args) {
System.out.println("Starting ...");
try {
ParameterizedTypeTest someInstance = new ParameterizedTypeTest();
checkParameterizedMethod(someInstance);
} catch (SecurityException e) {
e.printStackTrace();
}
}
}
If you run this code unsbfuscated, the output looks like this:
Starting ...
checking parameterized method ...
Found method someMethod
Parameter: class java.lang.Integer
Class: java.lang.Integer
But running the version obfuscated with proguard yields:
Starting ...
checking parameterized method ...
Found method someMethod
Failed: type ist not instance of ParameterizedType
These are the options I used for obfuscation:
-injars classes_eclipse\methodTest.jar
-outjars classes_eclipse\methodTestObfuscated.jar
-libraryjars 'C:\Program Files\Java\jre6\lib\rt.jar'
-dontskipnonpubliclibraryclasses
-dontskipnonpubliclibraryclassmembers
-dontshrink
-printusage classes_eclipse\shrink.txt
-dontoptimize
-dontpreverify
-verbose
-keep class **.ParameterizedTypeTest.class {
<fields>;
<methods>;
}
-keep class ** {
<fields>;
<methods>;
}
# Keep - Applications. Keep all application classes, along with their 'main'
# methods.
-keepclasseswithmembers public class * {
public static void main(java.lang.String[]);
}
# Also keep - Enumerations. Keep the special static methods that are required in
# enumeration classes.
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
# Also keep - Database drivers. Keep all implementations of java.sql.Driver.
-keep class * extends java.sql.Driver
# Also keep - Swing UI L&F. Keep all extensions of javax.swing.plaf.ComponentUI,
# along with the special 'createUI' method.
-keep class * extends javax.swing.plaf.ComponentUI {
public static javax.swing.plaf.ComponentUI createUI(javax.swing.JComponent);
}
# Keep names - Native method names. Keep all native class/method names.
-keepclasseswithmembers,allowshrinking class * {
native <methods>;
}
# Keep names - _class method names. Keep all .class method names. This may be
# useful for libraries that will be obfuscated again with different obfuscators.
-keepclassmembers,allowshrinking class * {
java.lang.Class class$(java.lang.String);
java.lang.Class class$(java.lang.String,boolean);
}
Does anyone have an idea of how to solve this (apart from the obvious workaround to put the relevant files into a seperate jar and not obfuscate it)?
Best regards,
Stefan
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用 proguard 很长一段时间后,我决定如何解决有关反射的问题(Guice 只是它的一个用例)。
只要没有类或方法名称作为字符串输入,反射就可以与 Proguard 一起使用。
也就是说,这段代码是有效的,经过 ProGuard 混淆后可以工作,
而这段代码则不起作用
。此外,Proguard 还会收缩未调用的方法和构造函数。因此,
Class.newInstance
方法将不起作用。不幸的是,通常的 Guice 绑定使用这种方法。这对 Guice 代码有一些影响。
Having used proguard for a good amount of time, here is how I decided to solve the issues regarding reflection (and Guice is only a use case of it).
Reflection can be used with Proguard as long as NO class or methods name are entered as Strings.
That's to say this code is valid and will work after ProGuard obfuscation
while this code won't work
Furthermore, Proguard will shrink uncalled methods and constructor. As a consequence, the
Class.newInstance
method won't work. Unfortunatly, usual Guice bindings works using this method.This has some consequences on Guice code.
在 JDK 5.0 及更高版本中编译时,需要“Signature”属性才能访问泛型类型。
使用 -keepattributes Signature 修复 ParameterizedType 的错误
The "Signature" attribute is required to be able to access generic types when compiling in JDK 5.0 and higher.
Use -keepattributes Signature to fix error with ParameterizedType
使用当前版本的 Proguard (4.7),我可以通过添加以下内容来使其工作:-
除了显式保留由 Guice 创建的任何类之外,例如
With the current version of Proguard (4.7) I was able to get it working by adding the following:-
In addition to explicitly keeping any class that is created by Guice eg
以下代码对我有用,也遇到了同样的问题。
-keepattributes Signature
是修复方法。Following code works for me, having had the same problem.
-keepattributes Signature
was the fix.