2

Say I am using a Java library that has the following method

public static SomeInterface foo();

The interface SomeInterface has multiple implementations, some of which are protected within the library's package. One of these implementation is TheProtectedClass

What would be the best way to check if the object returned by foo() is an instance of TheProtectedClass?

My current plan is to create an Utils class that lives within my project but in the same package as the protected class. This Utils can refer to TheProtectedClass since it is in the same package and thus it can check if an object is instanceof TheProtectedClass.

Any other ideas?

EDIT: Some people are asking "why" so here is more context.

I am using jOOQ and in some part of my code, I want to know if the Field instance that I have is an instance of Lower.

Currently, I use field.getName().equals("lower") but this isn't as robust as I'd like it to be.

I realize that since Lower is a protected class, it isn't part of the API and that it can change but I am ok with that.

GuiSim
  • 7,361
  • 6
  • 40
  • 50
  • 6
    You could do it through reflection, but why do you want to do this? – Sotirios Delimanolis Aug 20 '14 at 14:24
  • *multiple implementations, some of which are protected* what do you mean. A class has `public` or `default` visibility. – Braj Aug 20 '14 at 14:24
  • 1
    Surely, the best approach is to avoid having to do an `instanceof` check in the first place? – NPE Aug 20 '14 at 14:25
  • Is an instance *protected* when any of its super-classes or super-interfaces are `protected`, `private`, or package-private? – Mike Samuel Aug 20 '14 at 14:29
  • By protected I mean that the class itself is package-private. Sorry for the confusion. Also, @SotiriosDelimanolis I've added more information on why I want to do this. – GuiSim Aug 20 '14 at 14:34
  • 1
    Would be interesting to learn about the rationale behind the use-case. Maybe what you really want to do can be achieved in some other way using the jOOQ API? – Lukas Eder Aug 22 '14 at 11:10
  • I really want to know if the instance of Field> that I have is a Lower() expression. – GuiSim Aug 25 '14 at 19:40
  • @LukasEder Is it really a bad idea? One example where you could use this information is if you're creating a case insensitive comparison. Say I have `Field> a` that I want to compare in a case-insensitive way with `String b`. In my code, it is possible that `a` is an instance of `Lower` (which inherits `Field>`). Doing `a.equalIgnoreCase(b)` will result in `lower(lower(X)) = lower(Y)`. I could avoid the double lower(). Sure the lib could do that but this is just an example where I'd like to know. – GuiSim Aug 25 '14 at 19:48
  • Hmm, but you don't know if we implement support for the [`collate` clause](https://github.com/jOOQ/jOOQ/issues/2908), for instance, and then suddenly retrofit `Field.equalIgnoreCase()` to use `collate` internally, instead of `lower`. However, I can't quickly think of any better solution, right now... – Lukas Eder Aug 25 '14 at 21:48

2 Answers2

2
Class.forName("TheProtectedClass").isAssignableFrom(foo())

although it is a bad idea for many reasons. You're breaking the encapsulation and the abstraction here. If it's package-private, you shouldn't have to concern with it outside. If it's protected, you should explicitly inherit from it and use the API provided by class for this case.

The less obvious but more correct solution is to get an instance of TheProtectedClass, and compare it by

guaranteedTPCInstance.getClass().isAssignableFrom(foo())

, while still being kind of hacky, at least is more portable and OOPy IMO.

As to your idea of creating a class in the same package as TheProtectedClass to avoid being package-private - it's a viable solution, but a) it breaks the basic principle of encapsulation and the programming contract of the TPC class; packaging is done by library/class authors for a reason - to prevent irresponsible data access and using private API or undocumented proprietary methods, b) it's not always possible (and shouldn't be possible in case of properly designed library classes), since those classes can be not only package-private, but final or effectively final (anonymous inner classes etc) - for the reasons described by Bloch in EJ 2nd, "favor composition over inheritance" item, see also Good reasons to prohibit inheritance in Java? Use of final class in Java etc c) you can't do it with some Java library classes, as you can't define your class to be and use e.g. java.lang package. As such, the only "portable" solution is through reflection and through what I described.

tl;dr The fact you can piggyback another package by mimicking its package definition is an obvious C-style deficiency of Java's syntax (allowing programmer to do what he shouldn't be able to normally do; same goes with some specific reflection methods); hacks made this way are neither maintainable nor safe.

NOTE: If you you expect to do something in a internal implementation-dependent and, at the same time, portable and maintainable (e.g. impervious to implementation changes/class name changes etc) way, you're obviously expecting the impossible.

Community
  • 1
  • 1
  • I find this solution to be inferior to the _Utils_ solutions proposed in my post as it will not break compilation if `TheProtectedClass` changes name between library versions. – GuiSim Aug 20 '14 at 14:35
  • 1
    1) you asked for *other ideas* - the ain't any other way to do this AFAIR, so the fact its inferior (arguably) to your proposed solution only highlights that what you are trying to achieve is hacky by itself, 2) see my edit below for a more portable version, not dependent on TPC class name, 3) if you don't want to infer about the protected class from its name nor its instance object, how do you expect to show the application "I'm talking about *this* particular class"? –  Aug 20 '14 at 14:38
  • @LukasEder a) did you ever consider the fact that allowing inheritance in a non-explicitly-documented-for-inheritance case is an antipattern by itself? ... not to mention the inheritance by itself is commonly an antipattern, since most people just *can't* do it right, as shown by OP problem - and that's exactly what Bloch (and not only he, as the "prefer composition over inheritance" is a common good programming practice, not a synthetic rule, see http://en.wikipedia.org/wiki/Composition_over_inheritance) cdiscusses in-depth. –  Aug 22 '14 at 15:01
  • that's exactly why Bloch and many others (me included) say "if it's not explicitly designed to be extended, make it final to prevent inheritance. if it's explicitly designed to be extended, document it and make API straight so that it can be inherited without introducing errors and kludges"; since, in this case, the solution *is* a kludge due to OPs requirements vs functions offered by jOOQ's API, it proves that the class *shouldn't* allow inheritance to outside code. I won't digress on ways to do it and why to do it (there are good books about it), the fact still stands. –  Aug 22 '14 at 15:03
  • BTW, being package-private solves nothing if a programmer can emulate the package definition to force inheritance - so it's an antipattern by definition, a variant of *secure code design through obscurity* antipattern. –  Aug 22 '14 at 15:10
  • The fact that Java library made many bad design choices is obvious to everybody, Bloch's included (he even states that in preamble); it's not about *what is*, it's about *what should be*. The fact that Java lib does something is by itself not a proof it's a good way to do something. –  Aug 22 '14 at 15:25
0

It appears that the best solution is to create a package in your project that has the same package as the package-private class and either expose TheProtectedClass.class as a Class<?> or simply add a simple method that checks if your Object is instanceof TheProtectedClass.

This does not require reflection, it is fast and relatively safe (compilation will break if the package-private class changes name).

GuiSim
  • 7,361
  • 6
  • 40
  • 50