![]() |
|
|
|||||||
![]() |
Java - How to correctly by pass "protected" |
|
|
Thread Tools | Search this Thread |
|
|
#1 |
|
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? Roland J Rankin Jr |
|
|
|
|
#2 |
|
Posts: n/a
|
Roland J Rankin Jr wrote:
> 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 Patricia Shanahan |
|
|
|
#3 |
|
Posts: n/a
|
Roland J Rankin Jr wrote:
> 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... -- JSC JScoobyCed |
|
|
|
#4 |
|
Posts: n/a
|
Roland J Rankin Jr wrote:
> 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 John C. Bollinger |
|
|
|
#5 |
|
Posts: n/a
|
John C. Bollinger wrote:
> 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. Roland J Rankin Jr |
|
|
|
#6 |
|
Posts: n/a
|
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. Roland J Rankin Jr |
|
|
|
#7 |
|
Posts: n/a
|
child class declaration should read..
public class Child extends Parent but the results are the same. Roland J Rankin Jr |
|
|
|
#8 |
|
Posts: n/a
|
Roland J Rankin Jr wrote:
> 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 Chris Uppal |
|
|
|
#9 |
|
Posts: n/a
|
I wrote:
> 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 Chris Uppal |
|
|
|
#10 |
|
Posts: n/a
|
Roland J Rankin Jr wrote:
> 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 John C. Bollinger |
|
![]() |
| Thread Tools | Search this Thread |
|
|
Similar Threads
|
||||
| Thread | Thread Starter | Forum | Replies | Last Post |
| 100% GUARANTEED PASS....... IT CertificationzzzZ..... | Obaid | A+ Certification | 0 | 10-20-2009 09:49 AM |
| Is it easy to pass Certification Exams without coaching | rao | MCITP | 0 | 10-01-2009 06:42 PM |
| Pass Any Exam. Anytime. FreeExamKing.com | king | MCITP | 0 | 07-27-2009 10:36 AM |
| ONLY $30 to pass your exams 4 sure.FULL REFUND guarantee | ExamClear | A+ Certification | 0 | 12-19-2008 10:50 AM |
| Free VIP Exhibits Pass for NAB 2006 | jsolis@studentfilmmakers.com | DVD Video | 0 | 01-25-2006 11:07 PM |