Obfuscate two JARs separately with Maven / Proguard - java

I use maven to manage a core package and two appliaction packages that both depends on the core package. For technical reasons, I can't make a full assembly for each application package, which means that I've to distribute each application package with the core package as a separate JAR which will be put in the classpath of the application.
I also need to obfuctate my JARs. I can achieve this easily for a single assembly, however, I'm not sure if it is possible to obfuscate all classes while keeping my JAR separated ?
Someone has already been faced to this problem, and if so, is there any possibility to do this with maven and proguard ?
Thanks in advance!

Although I not sure if you could obfuscate two jars separately which depend on each other, but I have seen similar things done.
This can be achievedi by keeping some clean interface(s) between the two jars. This will allow you to keep the interface between the jars as unobfuscated and rest of the classes can be safely obfuscated without breaking the dependency.
This was done on one of the product I have worked on which exposed public APIs to clients to code to but the implementation classes were obfuscated.
This solution could be painful to implement practically and will depend on degree of inter dependency between your two jars.

Related

Maven Multi Module Project Structuring Issues

Well here is an interesting experience i had since last couple of weeks structuring my maven multi module project.
When i decided to use maven for my build life cycle management i had couple of reason that i wished to choose maven.
a. Mostly development teams are divided so that each team can work on separate Module within the project like Team-A to work on User Management System, Team-B to work on Authorization System, Team-C to work on Document Management System...and so on. Each team has java developers, testers, UI experts etc.
So the maven Project structure should be such that each team can independently work on their respective modules. They must be able to code, compile, build, test, deploy their module without having to compile, test modules belonging to other teams.
And thus i came to conclusion that each development module of the maven multi-module project must represent a Functional Module
After some discussions on forums i found people suggesting me to follow layered approach were child modules must be layers like controller-layer,service-layer,dao-layer etc. I did not pay heed to this advice because this not solving my purpose of teams working on individual module. This way for large project the build and deployment time for each team during development increases which does impact the project time-lines. sometimes the build and deploy time is upto 30 minutes say if there are 10 to 11 modules in the project.
But i did pay heed to a suggestion that keeping DAO layer separate for each module is not a good idea as DAO is highly granular and reused by other modules. and so the dependency of one module on other would would any how become greater.
I found a solution to this problem by creating a common module and moving DAOs and DOMAIN to the common module which will be inherited as a dependency by each module. And this seems to be a more viable option. Now the Project Structure looks like this.
Now when i build the project and run the webapp on server, It complains 404, Resource Not Found. I found that this is because the WEB-INF/classes folder is missing, src/main/java is missing in web-app module. I searched and found couple of links that suggested it is Deployment Assembly issue in Eclipse. So i need to manually create these folders and add in the deployment assembly because maven does not do it.
But the bigger questions are
do i need to move the Controller classes like com.mycompany.usermgmtsys.controller.UserMgmtController etc.. to src/main/java Or maven should find the controllers from the module jars included as dependency in WEB-INF/lib.
I dont want to do this i.e. putting java file in web-app. i want all the controllers should be available to the web-app as dependency for example WEB-INF/lib/usermgmtsystem.jar. But then wouldnt the Tomcat be looking for controllers in classes folder.
I dont know what should i do ? Any suggestions would be appreciated.
Its the way the eclipse render maven based project. It generally creates two structure. One based on master pom (parent project) and others based on individual module pom. however doing changes in any structure will reflect in the other one. As a practice I do changes in individual module folder structures and is more easy to read too.
Personally I try to avoid multi-module projects as, if you're using the Maven Release Plugin, you are locked into releasing all your modules together.
While this may sound like a convenience the problem arises when you need to do bug fix release to one of the modules - you end up releasing all the modules, not just the module with the bug fix, incrementing their version even though they haven't changed.
You also take a hit if you're running CI with multi-module projects - you're build typically runs over all modules from you root pom but if you're working in a particular module, you end up taking the hit of building those that haven't changed, in effect losing some of the benefits that the modularization was meant to provide.
So, go with independent modules but, and this is the important bit, create a common 'dependency' pom used by each.
A 'dependency' pom is a pom that standardizes all the dependencies across your projects and is different in that those dependencies are specified in the dependencyManagement section rather than the dependencies section (it also sets up standard plugin config, etc). This allows your project poms to specify the dependency pom as their parent and then declare the dependencies they need minus the versions, which are picked up from the 'dependency' pom and thus standardized across your projects.
If you are still concerned about being able to built everything, this can be achieved with a simple batch-file.
This is a good question. There are many aspects that must be considered for a useful project layout. I'd like to try to answer one which you didn't mention. Is your app extensible by users? If it is, then consider creating a separate module for your public API layer (service interfaces, DTOs used by those services, and Exceptions thrown by the services).
In our app, we have several maven modules per functional area. The idea is that a group worked on a feature within just one functional area and this isolation kept them messing with sources being modified by another group. Each functional area is broken down further in maven sub-modules we call "api", "domain", and "service" - we don't lump services/controllers, domain, and exceptions into a single module. The api module contains those classes we want to expose to customers for their customizations. Our service layer is the implementation of those interfaces. Further, we do not allow one module's service to call another module's service as this would bypass our service orchestration layer where customer can attach extensions to our services. Using separate maven modules per functional area helps enforce this.
We have other modules (internal-api, web, adapter) but they don't really add to this topic.
I figured out the issue. Controllers are presentation-layer components. The dispatcher expects the presentation layer components in the WEB-INF/classes folder in the target rather than looking for it in the lib. I am not sure if this is valid only for maven based structuring in eclipse. So finally these are the changes i have made
a. Created a src/main/java source folder in web-app. It is not generated by default in web-app module.
b. Add packages and respective controllers in the src/main/java folder.
So the final structure that i have (i am not pasting exact eclipse snapshot, this is generalized view)

Classloader to isolate a jar (class identity crisis)

I'm using jarX that has embedded dependencies that conflict with my own dependencies, so I'm creating a classloader to isolate jarX's dependencies from my main classloader.
jarX is outside my app's classpath, but my classes that use jarX's classes are in my classpath, so when I instantiate my classes loaded via the custom classloader, I run into the class identity crisis in the form of ClassCastException as the JVM's version of my classes are considered different from those loaded by my custom classloader.
I found this blog post where they solved a similar problem by only interacting with the custom classloader loaded classes via reflection, which seems to solve this problem.
It just feels like it should be easier than this. Does anyone know a better way to handle this problem?
The easiest way is to open jarX, remove the offending classes, and done. It is a bad practice to embed dependencies in a JAR unless that is JAR is meant to be used only as a standalone runnable fat-jar. JARs that are meant to be used as libraries should not embed dependencies.
When you notice that people package third-party classes in their JARs, I'd recommend pointing out to them that this is generally not a good idea and to encourage them to refrain from doing so. If a project provides a runnable fat-jar including all dependencies, that is fine. But, it should not be the only JAR they provide. A plain JAR or set of JARs without any third-party code should also be offered. In the rare cases that third-party code was modified and must be included, it should be done under the package namespace of the provider, not of the original third-party.
Finally, for real solutions to building modular Java applications and handling classloader isolation, check out one of the several OSGi implementations or project Jigsaw.
Can you post which jar is it and what are the classes that it overlaps, with the full stacktrace? Have a look at this tool I wrote to generate a list of duplicate classes in the WAR, there is an option to exclude duplicates of the same size.
These are some measures that can be done to solve this:
Try to reduce the number of duplicates by doing a case by case analysis of why the overlap exists. Add maven exclusions for jars that are complete duplicates.
Check if there is a version of the same jar without the dependencies that you could use, which jar is it, xerces, etc?
If there is no jar without dependencies, you can you exclude the other jar that overlaps jarX and see if the application still works. This means all components that need the jar have a compatible version of the jarX library
Separate the application into two WARs each with the version of the library you need. This will reduce the number of libraries in which
These where measures that are likelly to be more maintainable long-term
If the previous measures do not work:
open the jar, delete the duplicate classes and publish in the maven repository with a different name jarX-patched
you can configure nexus to serve a patched jar instead of an unpatched jar transparently
If your container supports OSGI that would be even better, but if you don't use a OSGI container for development as well, then the application would not work in development.

Is there a way to prevent developers to use a certain import?

I have an application that uses Jasper to generate reports. In order to encapsulate the complexity and provide a uniform interface with the Jasper API, I have created a "intermediate" interface that wraps the Jasper classes and delegates client calls to them. This will also make it easier to change the report machine in the future - to Crystal Reports, for instance.
The thing is, since the Jasper classes are in the classpath, developers (including myself) can accidentally use some of its classes directly in the business code, and that may pass unnoticed for a long time. I would like to avoid that, or at least be notified when that happens.
The environment is basically eclipse, maven, git, sonar, bamboo ci.
I'm sure this is not an uncommon scenario, so, what is the best way to deal? Design patterns, eclipse/maven plugins, sonar alerts? Or maybe something dead simple that I'm just not seeing?
In maven you can specify a library is for runtime only. This allows you to not compile against that library at all. If you don't use Jasper from maven, you could avoid including it at all. You can force this by adding an <exclusion> if it is a transient dependency.
You should have two separate eclipse projects: One for the reporting library, one for the rest.
The reporting library project contains your interfaces, the Jasper jar files and the Jasper-specific implementation of the interfaces.
The other project depends on the reporting library project (you can set project dependencies in the projects properties dialog under "Java Build Path" -> "Projects").
As the reporting project only exports the source folder to the other project, the jasper classes are not visible to it at development time.
I haven't used it much myself, but if you ever need more control over your dependencies you could try DCL Suite, an Eclipse plugin. It lets you define constraints between modules and you can declare the modules to be a class, a set of classes, packages, etc
That would only be possible if you handled classloading of Jasper and included it as a resource (a jar file) inside your own jar. Then no one would know it was available directly. Here's an example of how you can include jars inside your own jar file -> An embedded jar classloader in under 100 lines.

Generate minimized jar with only used classes

I'm in need of creating the minimal jar of utils library for use in Android. I'm using some methods from apache commons libraries (such as IOUtils, StringUtils). However, each such usage makes me import the whole library (commons-lang, commons-io etc.) which is absolutely acceptable under Tomcat (war's are mamoot-sized anyway), but absolutely unacceptable for Android project.
So, my aim is, to pack all used classes from dependencies into one jar - but only that classes that are needed. I remember once being in touch with maven plugin that done that task, unfortunatelly I can't remember its name nor find it via Google.
So please, do you know maven plugin that will do such minimization of dependencies, or any stand-alone tool that will do the same?
The maven plugin you can't remember is probably Apache Maven Shade Plugin, there is minimizeJar option. As Andreas_D noticed, this won't include classes, loaded with Class.forName, so you will need to implicity say in configuration, that you need them. Here is how i made maven to include jdbc driver in my single jar:
<filter>
<artifact>net.sourceforge.jtds:jtds</artifact>
<includes>
<include>**</include>
</includes>
</filter>
Excuse me, maybe i not clearly understood question. Obfuscator tool (i.e. ProGuard) could do that, isn't it? It packs several JARs into one and strips unused classes. If you don't need obfuscation/optimization (to prevent unwanted side-effects) then you could disable them, leaving "shrink" phase enabled.
In general it is not possible to automatically select all classes that are used by an application. Just think about what we can do with Class.forName(String name) or if we use a dependency injection container and declare types in external configuration files.
I guess if you use Eclipse to JAR the project it gives some options to do that while JARing :)
Maybe it will be useful.
Also you can collect your used library classes under a custom library and include this user created library in the project.

Jar configurations and their contents

While downloading Google Guice I noticed two main "types" of artifacts available on their downloads page:
guice-3.0.zip; and
guice-3.0-src.zip
Upon downloading them both and inspecting their contents, they seem to be two totally different "perspectives" of the Guice 3.0 release.
The guice-3.0.zip just contains the Guice jar and its dependencies. The guice-3.0-src.zip, however, did not contain the actual Guice jar, but it did contain all sorts of other goodness: javadocs, examples, etc.
So it got me thinking: there must be different "configurations" of jars that get released inside Java projects. Crossing this idea with what little I know from build tools like Ivy (which has the concept of artifact configurations) and Maven (which has the concept of artifact scopes), I am wondering what the relation is between artifact configuration/scope and the end deliverable (the jar).
Let's say I was making a utility jar called my-utils.jar. In its Ivy descriptor, I could cite log4j as a compile-time dependency, and junit as a test dependency. I could then specify which of these two "configurations" to resolve against at buildtime.
What I want to know is: what is the "mapping" between these configurations and the content of the jars that are produced in the end result?
For instance, I might package all of my compile configuration dependencies wind up in the main my-utils.jar, but would there ever be a reason to package my test dependencies into a my-utils-test.jar? And what kind of dependencies would go in the my-utils-src.jar?
I know these are a lot of tiny questions, so I guess you can sum everything up as follows:
For a major project, what are the typical varieties of jars that get released (such as guice-3.0.zip vs guice-3.0-src.zip, etc.), what are the typical contents of each, and how do they map back to the concept of Ivy configurations or Maven scopes?
The one you need to run is guice-3.0.zip. It has the .class files in the correct package structure.
The other JAR, guice-3.0-src.zip, has the .java source files and other things that you might find useful. A smart IDE, like IntelliJ, can use the source JAR to allow you to step into the Guice code with a debugger and see what's going on.
You can also learn a lot by reading the Guice source code. It helps to see how developers who are smarter than you and me write code.
I'd say that the best example I've found is the Efficient Java Matrix Library at Google Code. That has an extensive JUnit test suite that's available along with the source, the docs, and everything else that you need. I think it's most impressive. I'd like to emulate it myself.

Categories