7

I'm facing a very unique situation and need some advice: I'm working on a project which depends on an other project from my same company and now I need to apply some modifications to the dependency. The problem which I have is that the source code from the dependency has been lost, so the only thing I have is a maven dependency in the repository, with the corresponding jar file. On top of that, some of the classes in the Jar file where created using JiBX parser, mapping some XSD files which I neither have, and the resulting classes are synthetic and I found no decompiler able to handle them properly.

The only good thing of all of that is that the class which I need to change can be properly decompiled, so went for the following:

  • I decompiled the whole jar file and ended up with some classes (the JiBx ones) with empty or wrongly implemented methods.
  • I commented out the body of the wrong methods to have stub objects, applied the required changes to the right classes and recompiled.
  • I took the old Jar file, opened it and manually replaced the old class with the new one.

And the resulting Jar worked as expected.

Now my question is: Can I do all of that using Maven?

The idea would be to put the JiBX class files as resources, and keep the stub equivalents as source files and then let maven:

  • Compile everything as usual, putting all the compiled class files into target folder
  • Remove stub class files from target folder and replace them with the old precompiled class files
  • package the jar.

Which approach would you recommend?

UPDATE

I give some more details about the dependency project structure:

All classes are inside the same package:

my.project.domain.JiBX__c_GeneratedObfuscatedClass1.java
my.project.domain.JiBX__c_GeneratedObfuscatedClass2.java
my.project.domain.JiBX__c_GeneratedObfuscatedClass3.java
my.project.domain.CustomizableClass1.java
my.project.domain.CustomizableClass2.java
my.project.domain.CustomizableClass3.java

JiBX classes are not imported properly as dependency and if I try to put any of the CustmizableClasses into the project source and let the JiBX ones be in a dependency, the compiler reports missing methods.

I also tried using the Shade Plugin as suggested, but since I need to include the JiBX classes into my source path, I will end up having to include into package JiBX classes from jar dependency and compiled CustomizableClasses, but skipping CustomizableClasses from jar dep and compiled JiBX classes.

I looks like it can work, but I admit that I still didn't find the way of doing it. Any clues will be very welcomed.

UPDATE 2 (RESOLUTION)

I explain here how I finally managed this using the shade plugin as suggested, just in case someone else needs to do the same:

I finally created a project with the decompiled classes inside the same package, and left the methods which didn't want to be decompiled commented out.

In the pom.xml I added the following:

<build>
<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-shade-plugin</artifactId>
        <version>2.0</version>
        <executions>
            <execution>
                <phase>package</phase>
                <goals>
                    <goal>shade</goal>
                </goals>
                <configuration>
                    <artifactSet>
                        <includes>
                            <include>${project.groupId}:${project.artifactId}</include>
                            <include>TheDamnedProject:WithoutSources</include>
                        </includes>
                    </artifactSet>
                    <filters>
                        <filter>
                            <artifact>TheDamnedProject:WithoutSources</artifact>
                            <includes>
                                <!-- These classes will be taken directly from dependency JAR -->
                                <include>my/package/ClassWhichCouldNotBeDecompiled1.class</include>
                                <include>my/package/ClassWhichCouldNotBeDecompiled2.class</include>
                                <include>my/package/ClassWhichCouldNotBeDecompiled3.class</include>
                                <include>my/package/ClassWhichCouldNotBeDecompiled4.class</include>
                            </includes>
                        </filter>
                        <filter>
                            <artifact>${project.groupId}:${project.artifactId}</artifact>
                            <excludes>
                                <!-- These classes will be overridden by the ones inside the JAR -->
                                <exclude>my/package/ClassWhichCouldNotBeDecompiled1.class</exclude>
                                <exclude>my/package/ClassWhichCouldNotBeDecompiled2.class</exclude>
                                <exclude>my/package/ClassWhichCouldNotBeDecompiled3.class</exclude>
                                <exclude>my/package/ClassWhichCouldNotBeDecompiled4.class</exclude>
                            </excludes>
                        </filter>
                    </filters>
                </configuration>
            </execution>
        </executions>
    </plugin>
</plugins>

thanks!

Carles

Carles Sala
  • 1,989
  • 1
  • 16
  • 34
  • 1
    Do you need this to occur dynamically? Would there be a downside to deploying your altered JAR and just referencing it as a dependency? – Duncan Jones Feb 12 '13 at 10:59
  • 1
    I can live doing this manually, but it's the second time I need to modify this in a short period of time and I cannot guarantee that the next developer understands what's going on, so I prefer to make this as automatic as possible – Carles Sala Feb 12 '13 at 11:26
  • See also http://stackoverflow.com/q/1832853/545127 – Raedwald Feb 21 '13 at 00:53

1 Answers1

6

Here's how I would do that:

  • Create a new Maven project for this Jar file, with packaging type jar
  • Include the original Jar file as a dependency
  • Add the one decompiled .java file in the src folder

This should get you to a point where the .java file can be compiled, since the other classes from the jar file are available.

You now have two Jar files: one original, and one that should just contain the single recompiled and changed class.

Adding both to your application class path might work, but will depend on the order on the classpath.

If you want to end up with one jar file, I recommend to take a look at the Maven Shade Plugin (http://maven.apache.org/plugins/maven-shade-plugin/), which will allow you to create a new Jar file with contents from multiple sources. It will allow you to filter what goes into the new Jar file.

The Maven Shade plugin allows you to specify which classes from each artifact are included. It uses wildcards and include/exclude tags for this, as described here: http://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html

Once that Jar file is created, I would release it using the Maven Release plugin, and then include that artifact downstream. This will allow you to only update the patched Jar when it is really required, it probably doesn't have to be on every build. But that depends on your usage pattern.

For the version number of the new Jar file, I recommend to use a variation of the original one. Use the same groupId and artifactId, then modify the version number. If the original has 1.0.2, your new, patched file should be released as 1.0.2-1, to indicate that it's based on the 1.0.2 sources. If you need to make an additional change, release that as 1.0.2-2 and so on. This will make it easy to understand which version your patches are based on, and the incrementing patch number will give you a means to distinguis the releases.

nwinkler
  • 52,665
  • 21
  • 154
  • 168
  • Wow, that was a fast response! Sounds like an option, but I tried something similar: created a thinner jar containing only the JiBX classes and set that as a dependency of the project containing the classes to modify. Somehow it didn't find some methods in the JiBX classes... – Carles Sala Feb 12 '13 at 11:34
  • Are you sure that all dependencies are in the Jar file you created? The Shade plugin would allow you to specify the classes that you want to reuse from the original Jar, and then add your own. I recommend releasing the resulting Jar using a modified version number of the original (see answer, I've added some details). – nwinkler Feb 12 '13 at 12:12
  • nwinkler approach should work. Maybe something went wrong in your process. Maybe some confusion about the version or the content of the thinner jar.. – Samuel EUSTACHI Feb 12 '13 at 12:40
  • I gave it another try and I still see no way of doing this using Shade plugin: I need to include stub classes, otherwise the compiler reports missing methods in the JiBX classe (I tried again both importing the thin jar and the complete old jar). And the issue is that the stub objects are inside the same package as the classes to modify, so I found no way to tell Shade plugin how to include only some of the classes in the package. Any further clue? – Carles Sala Feb 12 '13 at 13:49
  • Did you see this page on the Shade Plugin? http://maven.apache.org/plugins/maven-shade-plugin/examples/includes-excludes.html It shows how to filter the classes from each package using wildcards (**). You should be able to narrow it down to individual classes. – nwinkler Feb 12 '13 at 14:05
  • I had to focus on other things during some months and left this untouched. Now I finally managed to do it using the shade plugin. Many thanks! – Carles Sala May 06 '13 at 11:05
  • +1 for the idea with the version number, because this little abuse prevent maven from loding the patched AND unpatched artifact together (when sombody somewhere forget to exclude the unpached Version) – Ralph May 08 '14 at 21:15