How to correctly by pass "protected"

R

Roland J Rankin Jr

Shortest possible explanation..

I'm using a jar I didn't write and have legal issues preventing me from
decompiling and recompiling as I see fit. Not to mention compatibility
and maintenance issues.

In general, I create an instance of their master object witch auto
magically hides all the networking, message encoding/decoding, and
transforms everything into an Events that I register as an event
listener to.

The particular event I listen fires multiple times, but all the data
that distinguishes instance X from instance y is hidden behind protected
methods.
e.g.
public class SkillGroupEvent extends Event
{
// blah
protected int getSkillGroupId();
protected String getSkillGroupName();
protected long getSkillGroupState();
// more blah
}

Now, I am trying to figure out what is the best way in the long term to
actually use (read get to) this data.

1. I could Decompile changed protected to public and call it a day. But
that's not an option for legal reasons.Plus it makes a head ache with
new versions and any coders that have to tread in my footsteps are not
going to like it one bit.

... Not going this way.

2. I could write my own SkillGroupEvent and hide the original by making
sure that mine was found on the class path before theirs. However this
seems a very brittle solution. (This would of course include solutions
revolving around custom class loaders..)Causing Long term issues with
compatibility and class path maintenance. (e.g what if they update their
package and my code no longer has all the correct internals, or methods)

.... Not going this way.

3. I could Extend their class. But since I'm not the one creating the
Event instance. I couldn't force their code to create an instance of my
class. I'd be stuck creating a constructor that Took an instance of
their Object and returned an instance of my object. (essentially a deep
copy constructor) That was basically a thin wrapper to expose the
protected data to my package. I lose the ability to extend from a common
class. Not a major issue, since their events don't correspond to my Base
classes anyway.

This solution seems the unfortunate choice, but some how feels ..
*thinks of good word* wasteful(?) Since now I need to Build an object to
expose their data and another object to act on the data. Three objects
versus two. (Data, data parser, data actor instead of Data, Data actor.)
I just some how dirty using this method, esp since I'll be building
roughly a thousand of these per minute, possibly much much more.

Probably stuck with this solution.


4. I could Write a class into their package that contained an instance
of their object and exposed the data, or Move my Event listener into
their package. Since I'm not extending their class I'm free to extend my
own classes. Which makes a maintenance issue for me. Long Term I'd like
to keep my code in my package. This feels like a dirty kludge. Works but
wrong at a fundamental/philosophical level. Since anyone that came after
me would now think their stock package supplied more functionality than
it actually does.

.... Not going this way.


So anyone have any alternatives? am I correct in thinking extending
their class with a sole constructor that takes an instance of their
class is the only way to go about this?
 
P

Patricia Shanahan

Roland said:
Shortest possible explanation..

I'm using a jar I didn't write and have legal issues preventing me from
decompiling and recompiling as I see fit. Not to mention compatibility
and maintenance issues.

In general, I create an instance of their master object witch auto
magically hides all the networking, message encoding/decoding, and
transforms everything into an Events that I register as an event
listener to.

The particular event I listen fires multiple times, but all the data
that distinguishes instance X from instance y is hidden behind protected
methods.
e.g.
public class SkillGroupEvent extends Event
{
// blah
protected int getSkillGroupId();
protected String getSkillGroupName();
protected long getSkillGroupState();
// more blah
}
....
So anyone have any alternatives? am I correct in thinking extending
their class with a sole constructor that takes an instance of their
class is the only way to go about this?

You could also use java.lang.reflect, and the setAccessible
method for the Method object representing the method you
want to call. Check the license wording to see if this is
permitted.

If you call protected methods in a class that was not
intended to be extended outside the jar, it may stop working
any time you install a new version. Since it is not part of
the interface they intended to externalize, the owners of
the code will feel free to change it whenever it is
convenient to them to do so.

It's worth thinking about alternative designs to avoid the
maintenance headache. Can you do anything with using more
event listener instances, and keeping the information you
need in the listeners? When you are registering a listener,
do you know about the instance?

Patricia
 
J

JScoobyCed

Roland said:
Shortest possible explanation..

I'm using a jar I didn't write and have legal issues preventing me from
decompiling and recompiling as I see fit. Not to mention compatibility
and maintenance issues.

In general, I create an instance of their master object witch auto
magically hides all the networking, message encoding/decoding, and
transforms everything into an Events that I register as an event
listener to.

The particular event I listen fires multiple times, but all the data
that distinguishes instance X from instance y is hidden behind protected
methods.
e.g.
public class SkillGroupEvent extends Event
{
// blah
protected int getSkillGroupId();
protected String getSkillGroupName();
protected long getSkillGroupState();
// more blah
}

Hi,

How about an object in your code, and you put it the same package name.
Let's say your code is:
foo.bar.mycode
and the event is
foo2.bar2.somecode.Event

You would write a foo2.bar.somecode.MyEventWrapper that would look like
this:

public class MyEventWrapper {

private Event mEvent = null;

public MyEventWrapper(Event evt) {
mEvent = evt;
}

public int getSkillGroupId() {
return mEvent.getSkillGroupId();
}

// ...
}

Now maybe there is some legal restriction that wouldn't allow you to
re-use their package name...
 
J

John C. Bollinger

Roland said:
public class SkillGroupEvent extends Event
{
// blah
protected int getSkillGroupId();
protected String getSkillGroupName();
protected long getSkillGroupState();
// more blah
}

Now, I am trying to figure out what is the best way in the long term to
actually use (read get to) this data.
3. I could Extend their class. But since I'm not the one creating the
Event instance. I couldn't force their code to create an instance of my
class. I'd be stuck creating a constructor that Took an instance of
their Object and returned an instance of my object. (essentially a deep
copy constructor) That was basically a thin wrapper to expose the
protected data to my package. I lose the ability to extend from a common
class. Not a major issue, since their events don't correspond to my Base
classes anyway.

This solution seems the unfortunate choice, but some how feels ..
*thinks of good word* wasteful(?) Since now I need to Build an object to
expose their data and another object to act on the data. Three objects
versus two. (Data, data parser, data actor instead of Data, Data actor.)
I just some how dirty using this method, esp since I'll be building
roughly a thousand of these per minute, possibly much much more.

Probably stuck with this solution.
So anyone have any alternatives? am I correct in thinking extending
their class with a sole constructor that takes an instance of their
class is the only way to go about this?

Protected methods and variables are barely worth the name. Unless the
class they belong to is final (in which case protected is equivalent to
default access) anyone can access protected members by subclassing.
Some variations on (3) would therefore be my choice. Try these on for size:

3a. Extend their event class with a class that holds an instance of the
original event and delegates method invocations to it. No need to make
a deep copy, or any copy at all. You can make public versions of the
methods you need, or leave them protected and count on accessing them by
virtue of your code being in the same package as the new event class.
This does depend on the event class exposing a suitable constructor.

3b. Extend their class with a class that provides static methods with
which to query an event instance for the data you need. For instance:

class AccessibleSkillGroupEvent extends SkillGroupEvent {

[...]

static int getSkillGroupId(SkillGroupEvent event) {
// Any class can invoke the protected methods of its
// superclasses
return event.getSkillGroupId();
}

[...]
}

You don't even need to instantiate an AccessibleSkillGroupEvent to use
its static methods to extract data from SkillGroupEvents -- no copying,
no extra objects, just get the data you want. You could even do (3a)
and (3b) together in the same class, though I'm not sure why you would
want to.


John Bollinger
(e-mail address removed)
 
R

Roland J Rankin Jr

John said:
3b. Extend their class with a class that provides static methods with
which to query an event instance for the data you need. For instance:

This feels like the right solution. It's the least amount of code, and
clearly self-documents that the sole purpose of this class is to work
around an oversight in the provided class.

The rest of the jar feels pretty intelligently laid out. Just looks like
someone went copy and paste crazy inside this one event.

Thanks for the refined suggestion.
Roland J Rankin Jr.
 
R

Roland J Rankin Jr

I think I missed something.. Given the code below..


package com.placebocode.test;
public class Parent
{
int x = 0;
public Parent()
{
}

protected int x()
{
return this.x;
}

}
/ ** new class and new Package **/
package com.placebocode.test2;
import com.placebocode.test.Parent;

public class Child
{
private Child()
{
}
public static int getX(Parent parent)
{
return parent.x();
}

}

/ * End Code */

I get the following error.
com/placebocode/test2/Child.java [13:1] x() has protected access in
com.placebocode.test.Parent
return parent.x();
^
1 error
Errors compiling Child.


Which I found really surprising. I can change the Child class package
declaration to match the parent and everything works. but if it's in a
different package. It refuses to compile.

I guess I'm back to answer 3a. he he.
 
R

Roland J Rankin Jr

child class declaration should read..

public class Child extends Parent

but the results are the same.
 
C

Chris Uppal

Roland said:
Which I found really surprising. I can change the Child class package
declaration to match the parent and everything works. but if it's in a
different package. It refuses to compile.

Maybe I'm misunderstanding the suggestion, but I don't think protected access
works that way. If you have a class Parent, and a subclass Child (in a
different package) then the only way that code in Child can call protected
methods of an instance of Parent, is via an object that is statically known
also to be an instance of /Child/. I.e. it can call:

self.protectedMethod();
or:
super.protectedMethod();

since "self" is statically known to be a Child, but it cannot call:

Child aChild = // ...whatever...
aChild.protectedMethod();

Going back to your problem, there are a few ways that you could evade the
restriction that have not yet been mentioned, using JNI, or doing on-the-fly
bytecode re-writing, for instance. But I don't think that anything makes as
much sense /in the long term/ as getting onto the supplier of this JAR file and
explaining what's broken and getting them to fix it. They will presumably
either agree that its a bug and schedule a fix, or at least explain that you
are doing it wrong and show you how to do it right.

That leaves you with the question of how to get around it in the short term --
don't reject a solution on the basis that it's a kludge, you that don't want to
or can't support it forever. To me, the most reasonable short term
possibilities are to put a simple forwarding class into their package (assuming
it's not sealed) or to use Patricia's suggestion of a reflection-based
workaround.

-- chris
 
C

Chris Uppal

I said:
since "self" is statically known to be a Child, but it cannot call:

Child aChild = // ...whatever...
aChild.protectedMethod();

Sorry, that's perfecly legal. The example should have read:
since "self" is statically known to be a Child, but it cannot call:

Parent aParent = // ...whatever...
aParent.protectedMethod();

Apologies for the confusion.

-- chris
 
J

John C. Bollinger

Roland said:
child class declaration should read..

public class Child extends Parent

but the results are the same.

Sorry, my bad. You can make 3b work as a convenient wrapper for 3a, but
not directly as I wrote it. That static methods cannot directly access
protected members of a superclass trips me up occasionally.


John Bollinger
(e-mail address removed)
 

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,997
Messages
2,570,241
Members
46,830
Latest member
HeleneMull

Latest Threads

Top