Hi,
Having some problems using Proguard on a rather
large application, basically I'm seeing this error
message after obfuscation:
Exception occurred during event dispatching:
java.lang.AbstractMethodError
at javax.swing.JTree.setModel(JTree.java:693)
at com.wordmap.toolset.ak.run(Unknown Source)
at java.awt.event.InvocationEvent.dispatch(
InvocationEvent.java:149)
at java.awt.EventQueue.dispatchEvent(
EventQueue.java:332)
This is using windowsNT4.0sp6, j2se 1.3.1_06 and
proguard 1.4.
I was wondering if theres any known problems in
this area, the code in question is too big, clunky &
copyrighted to forward on..
The package in question has a customised tree
component that extends JTree (mostly to add
autoscrolling & a custom page up & down key
action) dosnt attempt to override setModel() at all,
it overrides JTree's no-parameter constructor with a
simple super().. nothing too fancy -- Its
corresponding model is in the same package and
implements TreeModel, but things dont seem to be
getting that far. Code bugs out from an internal
Runnable class used to swap the tree model from
the event thread SwingUtilities.invokeLater() style,
this itself in from an asyncronous jdbc loading
thread ~ This object loader setup may be more
suspect in terms of class depth & complexity for
Proguard.
I'll try to keep plugging away at it until I can break
the problem down some more.. but right now I'll
have to try to swap back to retroguard to get a
shipable app out to the testers -- been having
problems with the obfuscated jar here too..
different problems though.. maybe retroguard
dosnt like 1.3.1_06; I'll drop back a few jvm
versions too see what happens, cant think of any
other changes to the app thay may have effected all
this.
Thanks,
Richard
Logged In: YES
user_id=234263
Might be a clue.. Just found the culprit behind my
retroguard problems, dropping back to 1_3_1_02 didnt
help.. eventually I realised that I'd updated ant to 1.5.1
over the past few months, going back to ant 1.4.1 and
the build works as before, no more unknown methods
or missing fields; again this is retroguard but given
proguards hertitage and the simularity of the error
messages.. need to investigate whats been changed
within ants javac (most likely) or jar tasks.
Logged In: YES
user_id=555208
The line number in your exception seems to correspond to a
method call inside the setModel method. In JDK 1.3.1_01 it is
clearToggledPaths() that is being called; I'm not sure if
it's still the same in JDK 1.3.1_06. It's a protected method
that shouldn't be causing any problems. The method is in a
library class and libraries remain unchanged.
Some thoughts:
- You've probably already tried to remove all class files and
recompile your application? Sometimes old class files still
hang around, after their source files have been removed.
Also, some IDEs recompile JDK classes to your output path
when you've browsed to them. Duplicate copies of Swing
classes could really mess things up.
- You're not trying to process the Swing classes as part of
the -injars options?
- You're not using the -ignorewarnings option and ignoring
some vital warnings?
ProGuard doesn't reuse any obfuscation code or shrinking code
from RetroGuard, just class parsing code. It seems unlikely
something is going wrong there.
You could send me your configuration file and the textual
output of ProGuard. If you want to create a simple example,
the component that extends JTree sounds like a good starting
point.
Eric.
Logged In: YES
user_id=234263
Ok, back working on this after the weekend; I'll try to
push the retroguard oddies to one side then.. although
the switch from ant 1.4.1 to 1.5.1 seems to be the root
cause (assume 1.5.1 passes different default javac
parameters - different source target?) ..even when using
the self same build.xml file.. very odd
Bit of history here - this project I'm working on is a
longstanding one, the build process including
retroguard was put in place at the end of 2000 and has
been working successfully across the jvm versions
since.. we haven't done any releases since the summer,
but on Friday I needed to add a small customer mod
(couple of extra reports, very minor change) and re-
build and much to my horror retroguard fluffed it.. at
the time I just decided it was finally time to retire
retroguard and I've been using proguard on my own
projects as a worthy successor, but after a quick config
change and rebuild proguard wasn't fairing any better..
with time pressing and not wanting to introduce
anything radically new into the build process I had to
reverse course again and find out why retroguard was
breaking.. Much of the problems were hidden because
the only really big change to my setup since the last set
of builds is my recent upgrade from IntelliJ Idea2.6 to
Idea 3.0; apparently in that upgrade the internal
versions of ant shipped with the IDE changed from 1.4
to 1.5.1. So now I'm trying to break the problems down
properly; the build.xml and proguard config files are
attached along with a log of the build & run.. I'm usually
very careful about wiping any old flaky classes, or
anything that might creep into the build, the directories
get nuked from orbit "just to be sure" at the start.. I'm
equally scruples on my environment & path settings
including wiping the extra java*.exe from the windows
dirs to ensure the only java executables are the ones in %
JAVA_HOME%/bin.
The build results are run from outside Idea this time, I
get much the same result; although significantly
less "duplicate classes" warnings, running ant from
within Idea I'll get 162 such warnings, outside just the
eight or so.. I'd guess Idea is additionally passing my
libdirs in the classpath or something, most of the
warnings are about wc3 packages like sax & jaxp etc..
which I'd expect too see duplicated ad-infitum in
xerces, jdom etc.. despite this change the end result is
the same java.lang.AbstractMethodError..
Richard
build config file & cmd log
Logged In: YES
user_id=234263
Finished trying to create a simple example with a JFrame
and one other component that extends JTree,
frustratingly that obfuscates and runs OK. To satisfy my
own paranoia I've also tried using ant 1.4.1 to build the
project, and that creates a jar with exactly the same
problem, so the retroguard stuff is quite a separate
issue.
One interesting step forward is I tried a build passing -
dontshrink to proguard, and that version appears to
work (at least no AbstractMethodError so far).
But Im unsure of how to progress the debugging to find
out what is being inappropriately shrunk..?
Logged In: YES
user_id=234263
..couple more notes:
The RetroGuard problems I originally had were very silly;
the ant 1.4.1 thing was a misnomer the problem turns
out to have been running retroguard under j2se 1.4,
which is the standard jvm for IntelliJ Idea.. it doesnt
complain at all but the result jar is un-useable full of
missing fields & methods.. Because I ran ant 1.4.1 from
my command line after Id already dropped back to j2se
1.3.1_02, and it then worked I didnt twig the real issue,
so thats one mystery less.
Still got the same problem with Proguard at the
moment, although using dontshrink will produce a
working set of jars; my confusion over the number of
warnings was the similar to above.. If I run proguard
under 1.4; Ill get 162 warnings about duplicate classes
because all the xml parser stuff is duplicated (quite
correct) again doing from the command line Ill only get
8 such warnings because Im going though 1.3.1_02. I
could fix that by changing the build.xml classpath; but
it doesnt seem to effect this AbstractMethodError.. Also
tried dumping out all the usage, mapping logs etc.. but I
cant spot anything obviously wrong with them.
Richard
Logged In: YES
user_id=555208
The original RetroGuard doesn't work with JDK 1.4, but
Thorsten Heit is maintaining an updated version that
solves this problem. It also adds a few other features,
although it doesn't shrink. You can find it at
http://javaguard.sourceforge.net/
For figuring out what's going wrong with the
application that is shrunk with ProGuard, you should
look at line 698 in javax.swing.JTree.setModel, as
reported in the stack trace. The source code should be
in the src.jar of your JDK; you can easily browse to it
using IntelliJ IDEA. If the method called on that line
is implemented somewhere in your own code, that's a
helpful indication. If the corresponding abstract
method in the JDK is in private or package visible
class, the option -dontskipnonpubliclibraryclasses will
help (it uses a lot of memory though). Explicitly
keeping the unjustly removed method should always solve
the problem. It would be nice to know its cause though.
Some notes with respect to your configuration file:
- As of ProGuard 1.4, native method names and their class
names should be preserved by specifying:
-keepclasseswithmembernames class * {
native <methods>;
}
- You shouldn't have to preserve any java run-time
library classes, since they always remain unchanged in
rt.jar. So you can remove this line:
-keep public class java.util.TimerTask
Eric.
Logged In: YES
user_id=234263
That seems to have narrowed down the cause; line 698
was treeModel.addTreeModelListener
(treeModelListener).. which was indeed implemented by
the super class of my treemodel. I've knocked together
a simple testcase app that illustrates the issue (zip
attached)..
The -keep public class java.util.TimerTask in my build
was only because I've included the class TimerTask
from the rt.jar in my jar resources.. bit naughty of me,
but including it allows my application to run under jdk
1.2.. So in this one case for backwards compatibility it
was necessary to protect it.
All that Retroguard stuff was mostly a deadline imposed
panic, I used JavaGuard before -- infact my RetroGuard
isnt quite the public version, it contains all kinds of
patches from the newgroups discussions before
JavaGaurd & Proguard kicked off.. which is maybe why it
remained so quite when I bodged the jvm -- I plumb
forgot that ant picks its jdk from the running jvm
instance.. and in Idea 3.0 that changes to 1.4 doh!
Hope the test case is useful,
Richard
Logged In: YES
user_id=555208
The problem appears to be caused by what I call a
retro-fitted interface: interface I contains method m,
class A implements method m, class B extends A and
implements I. A while ago, I had solved the problem
with referencing retro-fitted interface methods, but
now it pops up again for library interface methods.
Surprising that noone had noticed this before, although
the programming style is somewhat unusual.
I think changing body of the if-clause in
proguard/shrink/UsageMarker.java, around line 278,
solves the problem:
if (recurse)
{
String name =
libraryMethodInfo.getName(libraryClassFile);
String type =
libraryMethodInfo.getDescriptor(libraryClassFile);
// Mark all implementations of the method.
// Library class methods are supposed to be
used by
// default, so we don't want to lose their
redefinitions.
//
// For an abstract method:
// First go to all concrete classes of
the interface.
// From there, travel up and down the
class hierarchy to mark
// the method.
//
// This way, we're also catching
retro-fitted interfaces,
// where a class's implementation of an
interface method is
// hiding higher up its class hierarchy.
//
// For a concrete method:
// Simply mark all overriding
implementations down the
// class hierarchy.
libraryClassFile.accept(
(libraryMethodInfo.getAccessFlags() &
ClassConstants.INTERNAL_ACC_ABSTRACT)
!= 0 ?
(ClassFileVisitor)
new ConcreteClassFileDownTraveler(
new ClassFileUpDownTraveler(true, true,
false, true,
new NamedMethodVisitor(this, name, type))) :
(ClassFileVisitor)
new ClassFileUpDownTraveler(false,
false, false, true,
new NamedMethodVisitor(this, name, type)));
}
Please let me know if you get a chance to try it out.
Eric.
Logged In: YES
user_id=234263
Thanks for that Eric, only just got round to it after
Christmas and all, your fix seems to work fine with our
code now; I've also added the patch for the 'class
reference in inner class' problem (bug #640658)
although it isn't an issue within our code.
Thanks also for worrying about my somewhat unusual
programming style (grin), I've completed some major
refactoring for our next release version that does away
with this retro-fitted interface artefact althougher.
Richard