Using Proguard with a library has a @Service bean which should autowire
I have a library Common.License which I am obfuscating with Proguard:
<plugin>
<groupId>com.pyx4me</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<obfuscate>true</obfuscate>
<options>
<option>-dontoptimize</option>
<option>-renamesourcefileattribute SourceFile</option>
<option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,Enclosi开发者_JAVA百科ngMethod</option>
<option>-keep public class * { public protected *;}</option>
<option>-keepclassmembernames class * {java.lang.Class class$(java.lang.String); java.lang.Class class$(java.lang.String, boolean);}</option>
<option>-keepclassmembernames class * {com.common.license.LicenseSessionStore licenseSessionStore; com.common.license.LicenseStore licenseStore;}</option>
<option>-keepclassmembers enum * {public static **[] values(); public static ** valueOf(java.lang.String);}</option>
<option>-keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve();}</option>
</options>
<libs>
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jsse.jar</lib>
</libs>
<addMavenDescriptor>false</addMavenDescriptor>
</configuration>
</plugin>
This library has a Spring bean annotated with @Service:
@Service
public class LicenseServiceImpl implements LicenseService {
@Autowired(required = false)
LicenseSessionStore licenseSessionStore;
@Autowired(required = false)
LicenseStore licenseStore;
...
}
I use this library in a web service Company.License where I want the LicenseService to autowire:
@Component
public class BackgroundTasks {
@Autowired
ScheduledExecutorService scheduledExecutorService;
@Autowired
LicenseService licenseService;
...
}
So Company.License has a dependency on Common.License. If I obfuscate Common.License then licenseService
will not autowire in BackgroundTasks
. The only way I could work around this was to define licenseService explicitly as a bean:
@Bean(name = "licenseService", autowire = Autowire.BY_NAME)
public LicenseService getLicenseService() {
if (licenseService == null) {
licenseService = new LicenseServiceImpl();
}
return licenseService;
}
I should not need to explicitly declare this as a bean like this as I have already annotated the class with @Service
which should be enough to make the autowiring of licenseService
in BackgroundTasks
Spring-magically work. But it doesn't!
What is Proguard specifically doing to make this not work? Is there anything I can do in the configuration of Proguard to make it more Spring friendly?
Grant
A big thank you to Eric Lafortune for helping point me in the correct direction here:
http://sourceforge.net/projects/proguard/forums/forum/182456/topic/2547498
Here's the working pom file addition specifying the plug-in and the options required:
<plugin>
<groupId>com.pyx4me</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>proguard</goal>
</goals>
</execution>
</executions>
<configuration>
<obfuscate>true</obfuscate>
<options>
<option>-dontoptimize</option>
<option>-keepdirectories</option>
<option>-renamesourcefileattribute SourceFile</option>
<option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,*Annotation*,EnclosingMethod</option>
<option>-keep public class * { public protected *;}</option>
<option>-keepclassmembernames class * {java.lang.Class class$(java.lang.String); java.lang.Class class$(java.lang.String, boolean);}</option>
<option>-keepclassmembernames class * {com.common.license.LicenseService licenseService; com.common.license.LicenseSessionStore licenseSessionStore;}</option>
<option>-keepclassmembers enum * {public static **[] values(); public static ** valueOf(java.lang.String);}</option>
<option>-keepclassmembers class * implements java.io.Serializable { static final long serialVersionUID; private static final java.io.ObjectStreamField[] serialPersistentFields; private void writeObject(java.io.ObjectOutputStream); private void readObject(java.io.ObjectInputStream); java.lang.Object writeReplace(); java.lang.Object readResolve();}</option>
<option>-keep @org.springframework.beans.factory.annotation.Service class *</option>
<option>-keep @org.springframework.stereotype.Controller class *</option>
<option>-keepclassmembers class * { @org.springframework.beans.factory.annotation.Autowired *; }</option>
</options>
<libs>
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jsse.jar</lib>
</libs>
<addMavenDescriptor>false</addMavenDescriptor>
</configuration>
</plugin>
NOTE! You need to use ProGuard 4.4, the latest version of ProGuard-Maven-Plugin (2.0.4) uses 4.3 so you need to edit:
{M2_HOME}\repository\com\pyx4me\proguard-maven-plugin\2.0.4\proguard-maven-plugin-2.0.4.pom
To have the 4.4 dependency (like this):
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard</artifactId>
<version>4.4</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
Here's another way to switch to version 4.4 of proguard (which is probably a bit better):
<configuration>
<proguardVersion>4.4</proguardVersion>
<obfuscate>true</obfuscate>
<options>
...
</options>
<libs>
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jsse.jar</lib>
</libs>
<addMavenDescriptor>false</addMavenDescriptor>
</configuration>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard</artifactId>
<version>4.4</version>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
</dependencies>
I had the same issue and the -keepdirectories directive helped solve the issue for me.
精彩评论