Extending/replacing a class without a public constructor

H

Hugh Beyer

I'm having a really frustrating problem and I hope you guys can give me
some help.

I'm trying to write a test suite for a graphics-heavy app that uses
MIDP/J2ME. These apps use the Graphics class to do their screen updates.

What I want to do is subclass the Graphics class with my own class that
captures all calls and writes to a log that my tests can later examine.
Unfortunately, all the constructors of the Graphics class are private. The
system passes in a Graphics class when it's time to update the screen, and
you can also create a graphics class through a static factory method
(Image.getGraphics()). But either way, I can't get in and capture the
method calls to the resulting Graphics object.

Is there any way at all to do this, or am I SOL? Can anyone think of
another way to accomplish what I want?

Hugh
 
J

John C. Bollinger

Hugh said:
I'm having a really frustrating problem and I hope you guys can give me
some help.

I'm trying to write a test suite for a graphics-heavy app that uses
MIDP/J2ME. These apps use the Graphics class to do their screen updates.

What I want to do is subclass the Graphics class with my own class that
captures all calls and writes to a log that my tests can later examine.
Unfortunately, all the constructors of the Graphics class are private. The

You are mistaken. Both Graphics and Graphics2D (the actual class you
are most likely to run into) have protected no-arg constructors, at
least in Java 1.4.
system passes in a Graphics class when it's time to update the screen, and
you can also create a graphics class through a static factory method
(Image.getGraphics()). But either way, I can't get in and capture the
method calls to the resulting Graphics object.

Is there any way at all to do this, or am I SOL? Can anyone think of
another way to accomplish what I want?

You can subclass either class with an implementation that delegates to a
System-created Graphics instance, with logging wrapped around the method
invocations. I suppose that's what you had in mind to begin with. If
aspect-oriented programming were deeply enough supported by Java then
this would be a perfect case for it, but as it is, you probably couldn't
catch the system's manipulations of a Graphics -- only your own code's.


John Bollinger
(e-mail address removed)
 
M

Mike Schilling

Hugh Beyer said:
I'm having a really frustrating problem and I hope you guys can give me
some help.

I'm trying to write a test suite for a graphics-heavy app that uses
MIDP/J2ME. These apps use the Graphics class to do their screen updates.

What I want to do is subclass the Graphics class with my own class that
captures all calls and writes to a log that my tests can later examine.
Unfortunately, all the constructors of the Graphics class are private. The
system passes in a Graphics class when it's time to update the screen, and
you can also create a graphics class through a static factory method
(Image.getGraphics()). But either way, I can't get in and capture the
method calls to the resulting Graphics object.

Is there any way at all to do this, or am I SOL? Can anyone think of
another way to accomplish what I want?

You could create an instrumented Graphics class (based on the source code to
Graphics, which is distributed with the SDK) and run your app with a
bootclasspath that finds this implementation of Graphics before the standard
one in rt.jar.
 
H

Hugh Beyer

The

You are mistaken. Both Graphics and Graphics2D (the actual class you
are most likely to run into) have protected no-arg constructors, at
least in Java 1.4.

I'm dealing with javax.microedition.lcdui.Graphics. It hasn't got a no-arg
constructor but bingo, does have an undocumented 2-arg constructor. I'm
going to give that a try with width, height as the args.

I've only just gotten comfortable with the idea that my source tree can
add to packages I don't own. If I can get this to work, I can subclass
Graphics and just do logging on the calls I care about.
You can subclass either class with an implementation that delegates to a
System-created Graphics instance, with logging wrapped around the method
invocations. I suppose that's what you had in mind to begin with. If
aspect-oriented programming were deeply enough supported by Java then
this would be a perfect case for it, but as it is, you probably couldn't
catch the system's manipulations of a Graphics -- only your own code's.

I see how I can do this once I can get to the constructor, but if there
were no available constructor would I still be SOL? I've got to subclass
the Graphics class or my production code won't be able to write to it; and
any subclass is required to call super() in its constructors, isn't it?
And it has to be a subclass or my paint routines won't accept it as a
legitimate Graphics to write to.

Hugh
 
S

Shane Mingins

Hugh Beyer said:
I'm having a really frustrating problem and I hope you guys can give me
some help.

I'm trying to write a test suite for a graphics-heavy app that uses
MIDP/J2ME. These apps use the Graphics class to do their screen updates.

What I want to do is subclass the Graphics class with my own class that
captures all calls and writes to a log that my tests can later examine.
Unfortunately, all the constructors of the Graphics class are private. The
system passes in a Graphics class when it's time to update the screen, and
you can also create a graphics class through a static factory method
(Image.getGraphics()). But either way, I can't get in and capture the
method calls to the resulting Graphics object.

Is there any way at all to do this, or am I SOL? Can anyone think of
another way to accomplish what I want?

Hugh


It doesn't sound easy but it does sound possible. If you follow this thread
on the JUnit newsgroup you may find some pointers and techniques that help.

http://groups.yahoo.com/group/junit/message/9649

HTH
Shane
 
H

Hugh Beyer

I'm dealing with javax.microedition.lcdui.Graphics. It hasn't got a no-arg
constructor but bingo, does have an undocumented 2-arg constructor. I'm
going to give that a try with width, height as the args.

I've only just gotten comfortable with the idea that my source tree can
add to packages I don't own. If I can get this to work, I can subclass
Graphics and just do logging on the calls I care about.

Argh. "Cannot create class in system package." So I can't use the constructor
unless I'm in the package and I can't be in the package, and without the
constructor I can't create a subclass.

Part of the problem is that since this has to run under the cellular device
emulator, I don't have much control over the environment.

Hugh
 
L

Liz

getInstance() ????


Hugh Beyer said:
Argh. "Cannot create class in system package." So I can't use the constructor
unless I'm in the package and I can't be in the package, and without the
constructor I can't create a subclass.

Part of the problem is that since this has to run under the cellular device
emulator, I don't have much control over the environment.

Hugh
 
J

John C. Bollinger

Hugh said:
I'm dealing with javax.microedition.lcdui.Graphics. It hasn't got a no-arg
constructor but bingo, does have an undocumented 2-arg constructor. I'm
going to give that a try with width, height as the args.

I've only just gotten comfortable with the idea that my source tree can
add to packages I don't own.

You can do this in some cases, but it is not generally a good idea. As
you found, sometimes you can't do it at all.
If I can get this to work, I can subclass
Graphics and just do logging on the calls I care about.


I see how I can do this once I can get to the constructor, but if there
were no available constructor would I still be SOL?

To subclass any class you need access to a constructor.
I've got to subclass
the Graphics class or my production code won't be able to write to it; and
any subclass is required to call super() in its constructors, isn't it?

If a constructor does not explicitly invoke a superclass constructor
then an invocation of super() is implicit.
And it has to be a subclass or my paint routines won't accept it as a
legitimate Graphics to write to.

It has to be a subclass of the class that the API uses. But that class
probably isn't javax.microedition.lcdui.Graphics -- it's probably a
superclass of that class. If it is, then it is certain that that class
has a protected constructor, or even a public one.

Remember that your subclass will not be doing anything directly -- it
can't, because it won't have anything of its own to paint _on_. It must
wrap a system-provided Graphics, as I described in my last message.
Here's a schematic example for a simple API to which the principle can
be applied:

package wb.acme.products;

import wb.Coyote;

public abstract class Anvil {

protected Anvil() {}

public squashCoyote(Coyote c) {}
}

==

package wb.acme.products.fy2004;

public class AnimatedAnvil {
AnimatedAnvil(int weight) {}

public squashCoyote(Coyote c) {}

public int getWeight() {}
}

==

package wb;

import wb.acme.products.Anvil;

public class RoadRunner {

Coyote hunter;

public void kickAnvil(Anvil a) {
a.squashCoyote(hunter);
}
}

===

Now suppose that an AcmeProductFactory provides a method that produces
Anvils. In fact, the runtime class of these objects is
wb.acme.products.fy2004.AnimatedAnvil in the current version of the
factory. Given an Anvil obtained in that way, you want to generate some
effect when its squashCoyote(Coyote) method is invoked (a log, a
fadeout, an epitaph...). You cannot subclass
wb.acme.products.fy2004.AnimatedAnvil, but you don't need to -- you only
need to subclass wb.acme.products.Anvil, like so:

package mypackage;

import wb.acme.products.Anvil;
import wb.Coyote;

public class AugmentedAnvil extends Anvil {
private final Anvil innerAnvil;

public AugmentedAnvil(Anvil a) {
innerAnvil = a;
}

public squashCoyote(Coyote c) {
innerAnvil.squashCoyote(c);
c.waveWhiteFlag();
}
}

Given you can then construct an AugmentedAnvil as a wrapper around the
AnimatedAnvil at hand (without even needing to know its actual runtime
class), and you can pass it around in place of the AnimatedAnvil it
contains. After it squashes a Coyote -- for which it will employ the
wrapped Anvil to do the real work -- it will cause that Coyote to wave a
white flag.

The same general programming idiom can very likely be applied to your
problem.


John Bollinger
(e-mail address removed)
 
H

Hugh Beyer

It has to be a subclass of the class that the API uses. But that class
probably isn't javax.microedition.lcdui.Graphics -- it's probably a
superclass of that class. If it is, then it is certain that that class
has a protected constructor, or even a public one.

Remember that your subclass will not be doing anything directly -- it
can't, because it won't have anything of its own to paint _on_. It must
wrap a system-provided Graphics, as I described in my last message.
Here's a schematic example for a simple API to which the principle can
be applied:

Way cool, and thanks for the example. I had been wondering about the
situation in which this pattern would be useful and that makes it clear.

Unfortunately, J2ME MIDP is way more restricted than you're thinking.
javax.microedition.lcdui.Graphics is a direct subclass of Object, and the
system passes it directly to a display's paint() method. So there's no
super/subclass relationship that I can exploit--my method either takes a
Graphics or it doesn't.

Arrgh very arrgh. But MIDP 2.0 lets me look at pixel values of an image--I'm
going to use the production paint() method to draw to a Graphics I created
using a factory, then draw by hand to another I create, then compare pixels.
It will be sensitive to the exact pixel location, which I don't love, but it
will let me test the basics.

Hugh
 
J

John C. Bollinger

Hugh said:
Unfortunately, J2ME MIDP is way more restricted than you're thinking.
Drat.

javax.microedition.lcdui.Graphics is a direct subclass of Object, and the
system passes it directly to a display's paint() method. So there's no
super/subclass relationship that I can exploit--my method either takes a
Graphics or it doesn't.

Bummer. I'm afraid I don't have any more ideas for you. I do find
myself thankful that I'm not currently working with J2ME, though. I
guess the API designers put an extreme premium on size, which is
understandable to some extent, but clearly the end product doesn't let
one do some of the things one sometimes wants to do.


John Bollinger
(e-mail address removed)
 
H

Hugh Beyer

Bummer. I'm afraid I don't have any more ideas for you. I do find
myself thankful that I'm not currently working with J2ME, though. I
guess the API designers put an extreme premium on size, which is
understandable to some extent, but clearly the end product doesn't let
one do some of the things one sometimes wants to do.

I just went through the process of squeezing an app into the Nokia Series 40.
I was counting every class definition, every method, and every object, no
matter how trivial (especially the trivial ones). I ended up merging a bunch
of classes that started out distinct. They probably made the right trade-off.

Hugh
 
N

news.skynet.be

Hello I am trying to do a similar thing by extending BufferedImage to my own
subclass,

I am a bit of a newbie at this Java game, only a few months. But what I am
trying to achieve is to utilise the undoManager from Swing with a buffered
image so that I can track changes to my image, by using a
UndoableEditListener. So I want to extend BufferedImage inorder to apply
the listener. Although when I try to extend I have the problem of (reported
by Eclipse):

Error Implicit super constructor BufferedImage() is undefined. Must
explicitly invoke another constructor BufferedImage001.java bufferedImage001
line 31

Now I looked at the demonstrtation in this post concerning the Anvil and the
Coyote, which seems to be the problem I am experiencing.. but I am not
getting very far with it... any chance of a nudge in the right direction.
Or an example would be perfect, although a little cheeky to ask I feel.

Thanks for taking the time to read.

regards
Martin
 
N

news.skynet.be

Ok I think I sorted it out myself... after a bit of further reading... it
was as the anvil/coyote experiment... define the super constructor:

class MyImage extends BufferedImage {

private Image img;

public MyImage(int width, int height, int imageType) {

super(width,height,imageType);


}

}
 
D

Dale King

Hello, Hugh Beyer !
You said:
screen are private.
The

I'm dealing with javax.microedition.lcdui.Graphics. It hasn't got a no-arg
constructor but bingo, does have an undocumented 2-arg constructor. I'm
going to give that a try with width, height as the args.

I've only just gotten comfortable with the idea that my source tree can
add to packages I don't own. If I can get this to work, I can subclass
Graphics and just do logging on the calls I care about.
the screen,
and own code's.

I see how I can do this once I can get to the constructor, but if there
were no available constructor would I still be SOL? I've got to subclass
the Graphics class or my production code won't be able to write to it; and
any subclass is required to call super() in its constructors, isn't it?
And it has to be a subclass or my paint routines won't accept it as a
legitimate Graphics to write to.

There is a more drastic route you can take, but it requires more
work on your part. Basically you can create your own wrapper API
for it. It would look something like this:
- Create an interface which contains the method signatures for
all of the methods in Graphics.
- Create an implementation of that interface that contains a
reference to an instance of the real lcdui.Graphics type that is
passed into the constructor. Its implementations of the interface
methods simply calls the corresponding methods on the
lcdui.Graphics instance.
- You can then overrid that class to add any functionality you
wanted to perform in the subclass you were trying to create.
- You rewrite mostof your application to work with the interface
instead of the lcdui.Graphics class. Since they have the same
methods that mostly involves changing a few variable types.
- For methods like paint that take the actual lcdui.Graphics
instance, you wrap that in the class you created above that adds
your additional functionlity and that is what the rest of your
code uses.

This is certainly a lot of work, but it is doable.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,744
Messages
2,569,483
Members
44,901
Latest member
Noble71S45

Latest Threads

Top