I have an eclipse based application which uses YFiles library. I want to obfuscate YFiles & adjust obfuscated classes of YFiles libraries in my code.
I am executing this obfuscation via a Maven build triggering an ant script. My ant-script has the logic of obfuscation. This looks like--
<project name="obfuscate">
<target name="obf-modeler">
<taskdef name="yguard" classname="com.yworks.yguard.YGuardTask" classpath="./lib/yguard.jar" />
<yguard>
<inoutpair in="yfiles.jar" out="obfyfiles.jar" />
<inoutpair in="<my-app-jar>" out="<my-app-jar>" />
<rename replaceClassNameStrings="true">
<keep>
<class classes="private" methods="private" fields="private">
<patternset>
<include name="com.<my-company-name>." />
</patternset>
</class>
<package>
<patternset>
<include name="com.<my-company-name>." />
</patternset>
</package>
</keep>
<adjust replaceContent="true">
<include name="plugin.xml" />
</adjust>
</rename>
</yguard>
</target>
I am obfuscating Yfiles & my code together so that YFiles obfuscation is incorporated in my code as well. I also have a patternset on class & package elements to tell YGaurd that "don't obfuscate my code, only adjust the YFiles obfuscation changes"
Unfortunately, if I run the maven build, Some public YFiles methods with some return type are not getting obfuscated.
For example -- y.base.NodeMap class has methods obfuscated which don't have a return type, other methods who return something are still having old method names.
Any clue what is going wrong in my patter-set. Also, if I remove this pattern-set, there is no issue in YFiles obfuscation. However, my code is getting obfuscated too in that case which I don't want.
Thanks & regards
Abhinaw
It seems that you are subclassing / implementing interfaces or classes of the yFiles library. Note that if you are subclassing a class and tell yGuard to not obfuscate the subclass, the entiry class hierarchy is kept as well (this is necessary for the classloader). Just exclude your classes that extend/implement yFiles API classes in your keep rule. A pitfall here are anonymous classes. To avoid this, transform your anonymous classes to outer or inner classes and exclude these classes explicitly in your keep rule.
Related
Based on suggestions from my previous question on programmers.SE, I have split my current project into three subdirectories (swing, common, and android) and created separate Ant scripts in each one. Now I easily created NetBeans projects in the swing and common and was able to set the proper dependencies to compile the Swing app. Then when I go to use classes from the "common" project, I realize that I need to have another Ant script for the Android build process.
So now I have four Ant scripts used to build different parts of my project, along with separate src, test, and other supporting directories for each project. The first problem I encountered is that both NetBeans and the ant script for my "android" project want to use "build.xml" in my "common" project for various build tasks, some of which have name clashes. I decided I want to consolidate all of these projects back into one directory with src, test, etc. subdirectories. The source code is already organized into separate packages for each of the projects and I thought this would make it simpler since I can have a single Ant build script with separate tragets for the Swing and Android builds.
Now the problem I am running into is that when I try to build the "android" project, it wants to build all the Swing classes as well. This brings up a lot of compiler errors. I have even modified the <javac> task in an attempt to exclude the bbct.swing package hierarchy from compileing:
<javac encoding="${java.encoding}"
source="${java.source}" target="${java.target}"
debug="true" extdirs="" includeantruntime="false"
destdir="${out.classes.absolute.dir}"
bootclasspathref="project.target.class.path"
verbose="${verbose}"
classpathref="project.javac.classpath"
fork="${need.javac.fork}"
excludes="${source.dir}/bbct/swing/**"> <------- here
<src path="${source.absolute.dir}" />
<src path="${gen.absolute.dir}" />
<compilerarg line="${java.compilerargs}" />
</javac>
Ant still insists on compiling my classes which use Swing, though.
So I have two questions:
What is the best way to organize this project? Would you suggest one of the two that I have tried or something else entirely?
If I stick with my most recent solution, how do I make javac ignore the Swing-based source files in my project?
Between How to exclude a source package using javac in Ant? and How can I exclude sources in a javac task in ant?, I found a solution using an <exclude> elements, rather than the excludes attribute. Here is the relevant <javac> task:
<javac encoding="${java.encoding}"
source="${java.source}" target="${java.target}"
debug="true" extdirs="" includeantruntime="false"
destdir="${out.classes.absolute.dir}"
bootclasspathref="project.target.class.path"
verbose="${verbose}"
classpathref="project.javac.classpath"
fork="${need.javac.fork}">
<src path="${source.absolute.dir}" />
<exclude name="bbct/swing/**" />
<src path="${gen.absolute.dir}" />
<compilerarg line="${java.compilerargs}" />
</javac>
Addendum:
I suspect that the core of this solution lies in using a path relative to the source attribute or the <src> element. This means that an excludes element should work just as well using a relative path. I haven't tested this yet, though.
I try to obfuscate my project, but not all code. I try obfuscate only code from 1 package.
How can i do it in yguard (or somewhere else, proguard?)?
Thanks!
From the documentation:
There are three possible ways of specifying which classes will be excluded from the shrinking and obfuscation process:
It looks like the second way will be most useful for you:
One can specify multiple java classes
using a modified version of a
patternset. The patternset's includes
and excludes element should use java
syntax, but the usual wildcards are
allowed. Some examples:
<class>
<patternset>
<include name="com.mycompany.**.*Bean"/>
<exclude name="com.mycompany.secretpackage.*"/>
<exclude name="com.mycompany.myapp.SecretBean"/>
</patternset>
</class>
I've developed a module for a Java project. The module depends on external library (fastutil). The problem is, the fastutil.jar file is a couple of times heavier than the whole project itself (14 MB). I only use a tiny subset of the classes from the library. The module is now finished, and no-one is likely to extend it in future. Is there a way I could extract only the relevant class to some fastutil_small.jar so that others don't have to download all this extra weight?
Obfuscation tools such as ProGuard usually provide a feature to remove unused classes (and even fields and methods) from the jar file. You have to be careful to verify everything still works, 'though, because you might be using reflecton to access classes or methods that ProGuard can't analyze.
You can use only that feature and already get quite some saving
Or you could combine it with other space-saving obfuscation techniques (such as class and method renaming) to save even more space at the cost of harder debugging (your stack traces will become harder to parse).
From the installation instructions of fastutil:
Note that the jar file is huge, due to the large number of classes: if you plan to ship your own jar with some fastutil classes included, you should look at AutoJar (also available at JPackage) to extract automatically the necessary classes.
As fastutil is LGPL open-source software, you could just copy the relevant source files to your project and drop that jar file. The compiler will then tell you if have all the files you need. Just keep the packages as they are and put a copy of the fastutil license file on top.
Yeah one crude is to have a backup of your original jar. then remove all unused class files from the jar. and there may be some internal references to other class which you can add as and when it is required. ie while executing it may throw a class not found exception so then you can add that class from the original jar to this jar.
For a project of any complexity, I would personally avoid Proguard for this very specific purpose of shrinking an external library like fastutil because doing so currently requires considerable configuration to specify all the jars that will be modified and those that are to be left intact. You will also have to specify the filters to get the source contents from your input jars into the correct output jars.
On top of that, the tool does not like to modify external jar files without having access to modify the application jar file. It will generate an error as a 'warning' even when only using the shrink option that indicates a library that is to be updated is referenced by a fixed jar file. If you are only shrinking the code and doing no optimizations or obfuscation, this requirement is an unnecessary limitation. In my case, this was forcing me to include a whole set of library references in my Proguard configuration as inputs when my only goal was to eliminate classes from the fastutil jar that I do not use.
I think Proguard could solve this issue with minor changes but for right now, I found its usage for the purpose to be frustrating and time consuming. Instead I offer up this solution for anyone who has this specific problem.
In this example, I use ant to clearly remove those primitive types that I do not use in my application and then remove the specific implementations of maps that I do not use. With this configuration, I reduced the jar file from 23Mb to 5Mb which was sufficient for my case.
<jar destfile="F:/Programs/Java/JARS/fastutil-8.5.6-partial.jar">
<zipfileset src="F:/Programs/Java/JARS/fastutil-8.5.6.jar">
<!-- eliminate keys of specific primitive types -->
<exclude name="it/unimi/dsi/fastutil/booleans/**"/>
<exclude name="it/unimi/dsi/fastutil/chars/**"/>
<exclude name="it/unimi/dsi/fastutil/doubles/**"/>
<exclude name="it/unimi/dsi/fastutil/io/**"/>
<exclude name="it/unimi/dsi/fastutil/longs/**"/>
<!-- eliminate maps of specific implementations -->
<exclude name="it/unimi/dsi/fastutil/**/*ArrayMap*"/>
<exclude name="it/unimi/dsi/fastutil/**/*AVLTree*"/>
<exclude name="it/unimi/dsi/fastutil/**/*CustomHash*"/>
<exclude name="it/unimi/dsi/fastutil/**/*Linked*"/>
<exclude name="it/unimi/dsi/fastutil/**/*RBTree*"/>
<exclude name="it/unimi/dsi/fastutil/**/*Reference*"/>
</zipfileset>
<zipfileset src="F:/Programs/Java/JARS/fastutil-8.5.6.jar">
<include name="**/*2ObjectFunction.class"/>
</zipfileset>
</jar>
While this is not the optimal solution, it is easier to setup and troubleshhoot than using Proguard.
It doesnt seem that when you combine these Fileset attribute like below:
eg:
<fileset dir="src">
<include name="gov/nasa/arc/mas/selenium/tests/*.java" />
<excludesfile name="${test.suite}.exclude" />
</fileset>
that it has the expected behavior which is to include all *.java under src but exclude all the file specified on the excludefile.
Is it possible to combine include and excludesfile or do you need to user a corresponding includesfile??
Its a shame that these things are not documented and its hard to find explanations on google.
Actually, I think the Ant Manual is pretty clear about these types of things.
What isn't clear to me is what it is that you want to do. Do you want to use external files for both your "includes" and your "excludes"? Or are you looking to have one override the other?
It is documented and should work: http://ant.apache.org/manual/Types/fileset.html
Note that in the excludesfile, "each line of this file is taken to be an exclude pattern." What does your excludesfile look like?
I need to set up a filter file for my findbugs ant script that scans only the src/* files and not the test/* files.
What is the syntax for checking all classes while ignoring any filename or package name with 'test' in the name?
FindBugs is actually scanning the compiled class files, not the sourcePath. If you are compiling your src/* and test/* files to the different directories, you could just use the nested <class...> element.
<findbugs home="${findbugs.dir}" output="xml:withMessages"
outputFile="${findbugs.report.xml}" jvmargs="-Xmx256M"
effort="max" projectName="${ant.project.name}"
auxClasspathRef="findbugs.classpath"
sourcePath="${src.dir}">
<class location="${src.classes.dir}"/>
</findbugs>
That won't work if src/* and test/* are both compiled to a single directory. In that case, use a filter file and exclude the packages or class names that correspond to tests.
<findbugs home="${findbugs.dir}" output="xml:withMessages"
outputFile="${findbugs.report.xml}" jvmargs="-Xmx256M"
effort="max" projectName="${ant.project.name}"
auxClasspathRef="findbugs.classpath"
sourcePath="${src.dir}"
excludefilter="exclude.xml">
<class location="${classes.dir}"/>
</findbugs>
where exclude.xml looks like:
<FindBugsFilter>
<Match>
<Class name="~.*Test$"/>
</Match>
<Match>
<Package name="~test\..*"/>
</Match>
</FindBugsFilter>
By the way, it is a good idea to cover unit tests with FindBugs as well. There is no reason for using lower quality standards towards tests. Bugs in test are just that, bugs.
Sure, if you run FindBugs first time, there might be many bug reports, but the bug count will come down overtime if you pay any attention to them.