How do I reflect a private static nested subclass? - java

First, I'm looking for an answer in Kotlin, but I'm interacting with a Java library.
I need to get an instance from a private static nested class, derived from an instance of the surrounding superclass.
Given you have these (simplified) nested Java classes
public abstract class GLFWKeyCallback extends Callback implements GLFWKeyCallbackI {
public static GLFWKeyCallback create(GLFWKeyCallbackI instance) {
new Container(instance.address(), instance);
}
private static final class Container extends GLFWKeyCallback {
private final GLFWKeyCallbackI delegate;
Container(long functionPointer, GLFWKeyCallbackI delegate) {
super(functionPointer);
this.delegate = delegate;
}
}
}
I get back a Container instance as a GLFWKeyCallback, by way of another external method. You can think of this method as:
public static GLFWKeyCallback getCallback() {
return GLFWKeyCallback.create(anInternalInstance)
}
in Kotlin:
val callback:GLFWKeyCallback = getCallback()
// I would now want to cast,
// or in other ways use callback
// as the GLFWKeyCallback.Container class it actually is.
val callbackAsContainer = callback as GLFWKeyCallback.Container // Error: Container is private
val ContainerClass = GLFWKeyCallback::class.nestedClasses.find { it.simpleName?.contains("Container") ?: false }!!
// Gives me a KClass<*> that I don't know how to use, can't find documentation for this kind of circumstance
// If using the class instance itself is not possible I would at least want to get the
// Container.delegate of GLFWKeyCallbackI
val delegateField = ContainerClass.memberProperties.findLast { it.name == "delegate" }!!
val fieldValue = field.get(callback)
// Error: Out-projected type 'KProperty1<out Any, Any?>' prohibits the use of 'public abstract fun get(receiver: T): R defined in kotlin.reflect.KProperty1'

Why you don't want to use Java reflection? You can use it also from Kotlin:
val callback = getCallback()
val field = callback::class.java.getDeclaredField("delegate")
field.isAccessible = true
val delegate = field.get(callback) as GLFWKeyCallbackI

You can still get the class via .getClass(). This example prints '5':
public class Example {
public static void main(String[] args) throws Exception {
Object o = Target.get();
Field f = o.getClass().getDeclaredField("field");
f.setAccessible(true);
Integer i = (Integer) f.get(o);
System.out.println(i);
}
}
public class Target {
public static Object get() { return new Inner(); }
private static class Inner {
private int field = 5;
}
}
If you know precise names:
Class<?> c = Class.forName("com.foo.pkgof.Target$Inner");
c.getDeclaredField("field");
works. Note the dollar. That's the separator to use between 'outer' and 'inner'.

Related

Idiomatic migration from Java to Kotlin of class that accesses inner class private members

I have a Java class (Outer) that uses an inner builder class (Outer.Builder), accessing the private variables as part of the construction, as below:
import java.io.PrintStream;
public class Outer {
private int mValue;
private Outer(Builder builder) {
mValue = builder.mValue;
}
public void printValue(PrintStream stream) {
stream.println(mValue);
}
public static class Builder {
private int mValue;
public Builder setValue(int value) {
mValue = value;
return this;
}
public Outer build() {
return new Outer(this);
}
}
}
used as follows:
class Main {
public static void main(String[] args) {
var builder = new Outer.Builder();
var outer = builder.setValue(42).build();
outer.printValue(System.out);
}
}
I've attempted to take advantage of Android Studio's ability to migration Java code to Kotlin, which has given me the following result:
import java.io.PrintStream
class Outer private constructor(builder: Builder) {
private val mValue: Int
fun printValue(stream: PrintStream) {
stream.println(mValue)
}
class Builder {
private var mValue = 0
fun setValue(value: Int): Builder {
mValue = value
return this
}
fun build(): Outer {
return Outer(this)
}
}
init {
mValue = builder.mValue
}
}
However, compilation fails, with:
Outer.kt:24:22: error: cannot access 'mValue': it is private in 'Builder'
mValue = builder.mValue
^
because (as the Kotlin documentation states):
In Kotlin, outer class does not see private members of its inner classes.
which this code runs afoul of in the init block, with:
mValue = builder.mValue
I'm aware that I can refactor this to not attempt this access (changing the Outer constructor such that it takes all the members, adding accessors to Outer.Builder for the necessary fields, etc), but I'd like to know whether there is an idiomatic Kotlin way to achieve this kind of builder pattern (with minimal modification to the initial Java class, if possible).
Kotlin has named arguments, so the whole Builder pattern is embedded into the language:
class Outer(private val mValue: Int = 0) {
fun printValue(stream: PrintStream) = stream.println(mValue)
}
//Usage:
fun main() {
val outer = Outer(mValue = 42)
outer.printValue(System.out)
}
However, this approach works nicely only for usage from Kotlin. For usage from Java, constructor should become private and traditional nested Builder should be declared:
class Outer private constructor(val mValue: Int) {
class Builder {
#set:JvmSynthetic // Hide 'void' setter from Java
var mValue: Int = 0
fun setValue(value: Int) = apply { this.mValue = value }
fun build() = Outer(mValue)
}
fun printValue(stream: PrintStream) = stream.println(mValue)
}
To preserve convenient creation of Outer from Kotlin, we need to declare an auxilary top-level function whose name is the same as a type which we can use to replicate the constructor:
#JvmSynthetic // Hide from Java callers who should use Builder.
fun Outer(initializer: Outer.Builder.() -> Unit): Outer {
return Outer.Builder().apply(initializer).build()
}
Usage from Java:
public class BuilderUsage {
public static void main(String[] args) {
Outer outer = new Outer.Builder().setValue(42).build();
outer.printValue(System.out);
}
}
Usage from Kotlin:
fun main() {
val outer = Outer { mValue = 42 }
outer.printValue(System.out)
}

What are the differences between instance final fields from Java and readonly instance fields from C#?

In general - equivalent of final field in Java is the readonly field in C#. But the more I read about C# the more I see that there are some differences in details.
I've found myself two differences:
Fields marked as readonly assigned as part of definition can be reasigned in constructor
In Java it is not possible to do that with final fields. Examples:
Example - C Sharp
public class Foo
{
public readonly int a = 1;
public Foo()
{
a = 2;
}
}
and now
Foo f = new Foo();
Console.WriteLine(f.a);
will give us 2 as an output
(side question - is this behavior can be actualy used for something useful? As far as I know I cannot assign value to base class' readonly field in dervied class)
Example - Java
class Foo {
private final int i = 3;
public Foo() {
// compilation error
// i = 2;
}
}
Orders of initalization of readonly and final fields in class hierarchy are different in both languages
In Java it will go from base class to dervied.
In C# it will go from derived class to base.
Example - C Sharp
Based on article Eric Lippert: Why Do Initializers Run In The Opposite Order As Constructors? Part One:
public class Print
{
public Print(string text)
{
Console.WriteLine(text);
}
}
public class Base
{
private readonly Print #base = new Print("Base class");
}
public class Derived : Base
{
private readonly Print derived = new Print("Derived class");
}
In case of calling new Derived() we will see:
Derived class
Base class
As far as I understood - this order of initalization guarantees that readonly fields are always initalized before usage. In case of following code (based on second part of Eric's article - Why Do Initializers Run In The Opposite Order As Constructors? Part Two):
public class Foo
{
}
public class Base
{
public Base()
{
if (this is Derived)
{
((Derived)this).danger();
}
}
}
public class Derived : Base
{
private readonly Foo derived = new Foo();
public void danger()
{
Console.WriteLine("access: {0}", derived.GetHashCode());
}
}
Calling new Derived() is safe.
Example - Java
Similar code in Java:
class Print {
public Print(String text) {
System.out.println(text);
}
}
class Base {
private final Print base = new Print("Base class");
}
class Derived extends Base {
private final Print derived = new Print("Derived class");
}
Call new Derived() will result with:
Base class
Derived class
So in case of following code:
class Base {
public Base() {
if (this instanceof Derived) {
((Derived)this).danger();
}
}
}
class Derived extends Base {
private final Foo field = new Foo();
public void danger()
{
System.out.println("access: " + field.hashCode());
}
}
The call new Derived() will result with NullPointerException
Question
My question is: Are there other differences (even small ones) between Java's final fields and readonly fields in C# ? To make question more clear - I have in mind only final instance fields in Java (so no static finals, no final variables, no other final "thigs")

Creating a class and creating an instance from a string

I have a problem in creating an object.
Basically I would like to create an object from a given class by taking originally a string. I know that using Class.forName(field) works, but not in my case and I will show you why below. I have thought about reflection but fear it will cause the same problem.
My code as of right now is (template is a String):
int n = template.length();
String field = at.getFieldName().trim();
field = field.substring(0, field.length() - 1);
Class<?> correctClass = Class.forName(field);
UniqueEntity<correctClass> ue = new UniqueEntity<correctClass>();
The error message I get is that correctClass cannot be resolved to a type.
Once you used Class.forName() method you got your Class instance (variable correctClass) invoke method getConstructor() or getConstructors() to get an instance of class Constructor. Once you get your instance of class Constructor invoke method newInstance() to get an instance of your class. Here is the example:
Class myClass = Class.forName(field);
Constructor constructor = myClass.getConstructor()
Object o = constructor.newInstance()
All this assuming that your class has default constructor.
In order for you to be able to create a UniqueEntity with the type of your reflective class, you need to pass the class type into a generic helper method.
private static <T> UniqueEntity<T> createEntity(Class<T> clazz) {
return new UniqueEntity<T>(clazz);
}
Code
import java.lang.reflect.Type;
public class Generic {
public static void main(String[] args) {
try {
String field = "java.lang.Integer";
UniqueEntity<?> entity = fromField(field);
System.out.println(entity);
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static UniqueEntity<?> fromField(String field) throws ClassNotFoundException {
return createEntity(Class.forName(field));
}
private static <T> UniqueEntity<T> createEntity(Class<T> clazz) {
return new UniqueEntity<T>(clazz);
}
private static class UniqueEntity<T> {
private final Type type;
public UniqueEntity(Class<T> clazz) {
this.type = clazz.getGenericSuperclass();
}
#Override
public String toString() {
return "UniqueEntity [type=" + type + "]";
}
}
}

Getting value of private not primitive field using reflection

Presume we have two different packages... one package can't be accessed but we like to know the value of a complex field called b.
public class A {
private String whatever;
private B b;
private static class B {
final ArrayList<Z> c = new ArrayList<Z>();
private void addItem(Z z) {
this.c.add(z);
}
private Z getItem(int nr) {
return this.c.get(nr);
}
}
}
public class Reflect extends A {
public static void main(String[] args) throws NoSuchFieldException, SecurityException {
Reflect ref = new Reflect();
Class getA = ref.getClass().getSuperclass();
Field getB = getDeclaredField("b");
getB.setAccessible(true);
Class bInst = getB.getClass();
Method bMeth = bInst.getMethod("getItem", Integer.TYPE);
Object zInst = bMeth.invoke(new Integer(123));
}
}
How can I get the value if I don't get the complex type B from the package ?
Still get java.lang.NoSuchMethodException: stackOver.A.getItem(int) even I set the field gstB accessible ....
The only thing you are missing is that getField only gives you public accessible fields.
Field getB = getA.getDeclaredField("b");
will give you any field of that class.
A longer example
class Main {
public static class A {
private String whatever;
private B b = new B();
private static class B {
final ArrayList<String> c = new ArrayList<String>();
private void addItem(String z) {
this.c.add(z);
}
private String getItem(int nr) {
return this.c.get(nr);
}
}
}
public static class Reflect extends A {
public static void main(String... ignored) throws Exception {
Reflect ref = new Reflect();
Class getA = ref.getClass().getSuperclass();
Field getB = getA.getDeclaredField("b");
getB.setAccessible(true);
Object b = getB.get(ref);
Method addItem = b.getClass().getDeclaredMethod("addItem", String.class);
addItem.setAccessible(true);
addItem.invoke(b, "Hello");
Method getItem = b.getClass().getDeclaredMethod("getItem", int.class);
getItem.setAccessible(true);
String hi = (String) getItem.invoke(b, 0);
System.out.println(hi);
}
}
}
prints
Hello
How can I get the value if I don't get the complex type B from the package ?
You can get it as an Object, and then use reflection to further discover the methods that it exposes.
Object bInst = ... // Get b through reflection
Class bClass = bInst.getClass();
Method[] bMeth = bClass.getMethod("getItem", Integer.TYPE);
Object zInst = bMeth.invoke(new Integer(123));
Use commons beanutils library and use following method, it is much cleaner than doing it yourself
PropertyUtils.getNestedProperty(ref, "b.propertyOfClassB");
replace propertyOfClassB with actual property name.

How can I access a method of an "unnamed" class?

public class Test {
public static void main(String[] args) {
DemoAbstractClass abstractClass = new DemoAbstractClass() {
private String val;
#Override
public void runner() {
val = "test";
System.out.println(val);
this.run();
}
public String getVal() {
return val;
}
};
abstractClass.runner();
/**
* I want to access getVal method here
*/
}
}
abstract class DemoAbstractClass {
public void run() {
System.out.println("running");
}
public abstract void runner();
}
Here, I'm declaring an abstract class DemoAbstractClass. I can obviously create a new class that extends this class and add this method to it. But, I would prefer not doing that in my scenario.
Is there any other way to access getVal method in above code??
You can't. You need to make a proper (non-anomous) class out of it. Make it an inner private class if you want to limit its scope.
Alternatively, you could use a StringBuffer and share a referense to it between the methods. Not extremely clean however.
Related question:
Accessing inner anonymous class members
Short of using reflection, you cannot as you have no access to the concrete type of the object to be able to bind the methodcall to
If you don want to do something like this in a sane manner, declare a named class and use that as the type of abstractClass
Unfortunately, if you cannot name the type, you cannot access the methods at the language level.
What you can do, though, is use the reflection API to get a Method object and invoke it on this object.
This, however, is pretty slow. A private class or private interface would be much faster.
I can obviously create a new class that extends this class and add this method to it.
You've already done this; the end result was an anonymous inner class: new DemoAbstractClass() { ... }; If you just moved that declaration into its own class -- you can even make it a private class -- you can access getVal.
Per your example above:
public class Test {
public static void main(String[] args) {
DemoClass abstractClass = new DemoClass();
abstractClass.runner();
/**
* I want to access getVal method here
*/
abstractClass.getVal(); // can do this here now
}
private class DemoClass extends DemoAbstractClass {
private String val;
#Override
public void runner() {
val = "test";
System.out.println(val);
this.run();
}
public String getVal() {
return val;
}
}
}
}
Another option is to make a StringBuilder a member of the main method and use the closure nature of anonymous inner methods:
public static void main(String[] args) {
final StringBuilder value = new StringBuilder();
DemoAbstractClass abstractClass = new DemoAbstractClass() {
#Override
public void runner() {
value.append( "test" );
System.out.println(val);
this.run();
}
};
abstractClass.runner();
// use val here...
String val = value.toString();
}

Categories