Kotlin reflection interoperability with Java - java

What are the caveats that a developer should be aware of while writing reflective code that works both with Java and Kotlin?
For example, I have an existing library that uses reflection and it works well with Java. However, when I use the same with Kotlin, my reflective code doesn't seem to pick up the annotations on fields.
Here are some of the differences that I noticed.
1. Acquiring a Class instance
// Example 1.1 - Java
Class<?> userClass = User.class; // From a class name
userClass = userInstance.getClass(); // OR from an instance
Getting a Java class instance in Kotlin
// Example 1.2 - Kotlin
val userClass = userInstance.javaClass // From an instance
I'm unable to use the .class facility or the .getClass() method in Kotlin as we do in Java.
2. Delegates
When I use delegated properties in a Kotlin class, the properties that I retrieve have the $delegate suffix. This is a bit contrary to the fields that we get in Java (I do understand Kotlin does not have fields, only properties). How does this affect meta-programming?
However, with delegates I see that most of the methods retain their behavior as they do in Java. Are there any other differences that I have to be aware of?
Making Java and Kotlin interoperable for me would require understanding about 1 discussed above, plus other limitations / differences that Kotlin brings to meta-programming.

For example, I have an existing library that uses reflection and it works well with Java. However, when I use the same with Kotlin, my reflective code doesn't seem to pick up the annotations on fields.
Can it be because the fields are private now?
Anyway, there are issues with annotations on fields at the moment, this will be fixed in on of the upcoming milestones.
Some other relevant issues:
https://youtrack.jetbrains.com/issue/KT-5967
https://youtrack.jetbrains.com/issue/KT-4169
https://youtrack.jetbrains.com/issue/KT-3625
I'm unable to use the .class facility or the .getClass() method in Kotlin as we do in Java.
Only the syntax is different: javaClass<C>() works exactly the same as C.class, and x.javaClass does the same thing as x.getClass()
When I use delegated properties in a Kotlin class, the properties that I retrieve have the $delegate suffix.
Minor correction: the fields have the $delegate suffix, not the properties.
However, with delegates I see that most of the methods retain their behavior as they do in Java. Are there any other differences that I have to be aware of?
The docs here give you a detailed description of how delegated properties are implemented.
Making Java and Kotlin interoperable for me would require understanding about 1 discussed above, plus other limitations / differences that Kotlin brings to meta-programming.
The more your Kotlin code resembles Java code, the smaller is the difference from the reflection point of view. If you write idiomatic Kotlin, e.g. use default parameter values, traits, properties, delegates, top-level functions, extensions etc, the classes you get differ from idiomatic Java, otherwise they are closely aligned.

Related

Kotlin scope functions are actually java anonymous classes?

I'm currently working on some old Java written Android project, but writing new parts in Kotlin which I'm not really familiar with. I need some way to unwrap nullable object(analogue of if let unwrappedMyVar = myVar else {} in Swift), to do this I use myVar?.let {} scope function which unwraps myWar and executes block in case it is not null. But now I'm actually curious how those scope functions are implemented in Kotlin, are the actually compiled to Java anonymous classes ? If so, then it can lead to the same problems that Java anonymous classes have. And it is quite easy to create the leakThank you !Kind Regards,Andre
The scope functions like let, apply, run, or also, as well as many more functions in the Kotlin standard library, are inline functions, which means that the lambdas that you pass to them get inlined in their bodies, and the transformed bodies then get inlined at the call site.
With the scope functions, the resulting bytecode is mostly equivalent to what you would get with just declaring a variable and using it after an explicit if-null-check.

What's the intended use of #JvmSynthetic in Kotlin?

I have come across the #JvmSynthetic annotation in kotlin-stdlib, and I'm wondering what it is for, but, unfortunately, it is undocumented. (UPD: it was at that moment)
As far as I understand, applying it to a program element will add the synthetic modifier to the corresponding bytecode elements. As a consequence, the element becomes invisible from Java:
class MyClass {
#JvmSynthetic
fun f() { }
}
Somewhere in Java code:
MyClass c = new MyClass();
c.f() // Error: cannot resolve method f()
But the same elements are still visible in Kotlin code:
val c = MyClass()
c.f() // OK
Is hiding declarations from non-Kotlin sources a valid use of #JvmSynthetic? Is it the intended use? What are the other appropriate use cases?
Since #JvmSynthetic hides functions from Java, they cannot be overridden in Java either (and when it comes to an abstract member, the calls then result into AbstractMethodError). Given that, can I use #JvmSynthetic to prohibit overriding members of a Kotlin class in Java sources?
In plain Java, synthetic methods are generated by the javac compiler. Normally the compiler must create synthetic methods on nested classes, when fields specified with the private modifier are accessed by the enclosing class.
Given the following class in java:
public final class SyntheticSample
{
public static void main(final String[] args)
{
SyntheticSample.Nested nested = new SyntheticSample.Nested();
out.println("String: " + nested.syntheticString);
}
private static final class Nested
{
private String syntheticString = "I'll become a method!";
}
}
when the SyntheticSample class accesses the nested.syntheticString field, it is indeed calling a static synthetic method generated by the compiler (named something like access$100).
Even if Kotlin exposes a #JvmSynthetic annotation that is able to "force" the creation of synthetic methods, I advice to not using it in normal "user" code. Synthetic methods are low-level tricks made by the compiler, and we should never rely on such things in everyday code. I think it's there to support other parts of the standard library, but you should ask the JetBrains guys directly if you're curious (try on the official Kotlin Discussion Forum)
First, to answer what synthetic methods actually are, let's have a look at the Java language specification:
11. A construct emitted by a Java compiler must be marked as synthetic if it does not correspond to a construct declared explicitly or implicitly in source code, unless the emitted construct is a class initialization method (JVMS ยง2.9).
The #JvmSynthetic annotation does exactly that: prevent access from source code. The method will still appear in reflection and is then marked as synthetic.
More precisely, from the Kotlin documentation (emphasis mine):
#JvmSynthetic
Sets ACC_SYNTHETIC flag on the annotated target in the Java bytecode.
Synthetic targets become inaccessible for Java sources at compile time while still being accessible for Kotlin sources. Marking target as synthetic is a binary compatible change, already compiled Java code will be able to access such target.
This annotation is intended for rare cases when API designer needs to hide Kotlin-specific target from Java API while keeping it a part of Kotlin API so the resulting API is idiomatic for both.
As described in the last paragraph, #JvmSynthetic is a tool for API design, which lets a library writer avoid automatic generation of Java equivalents. Probably the most popular use cases are Kotlin-only features, such as operator overloading, componentN() methods or properties, which may have a more idiomatic way to be exposed in Java.
It is noteworthy that the target of this annotations are property setters/getters, functions and fields -- basically everything that translates in Java to a method.
#Target([
AnnotationTarget.FUNCTION,
AnnotationTarget.PROPERTY_GETTER,
AnnotationTarget.PROPERTY_SETTER,
AnnotationTarget.FIELD])
annotation actual class JvmSynthetic

Java 8 add extension/default method to class

I am looking for a java equivalent to the C# extension methods feature. Now I have been reading about Java 8's default methods, but as far as I can see, I can only add these to interfaces...
...is there any language feature that will allow me to write an extension method for a final class that doesn't implement an interface? (I'd rather not have to wrap it...)
Java doesn't have extension methods. Default methods are not extension methods. Let's look at each feature.
Default methods
Both Java and C# support this feature
Problems solved:
Many objects may implement the same interface and all of them may use the same implementation for a method. A base class could solve this issue but only if the interface implementors don't already have a base class as neither java nor C# support multiple inheritance.
An API would like to add a method to an interface without breaking the API consumers. Adding a method with a default implementation solves this.
Java's or C#'s default methods are a feature to add a default implementation to an interface. So objects that extend an interface don't have to implement the method, they could just use the default method.
interface IA { default public int AddOne(int i) { return i + 1; } }
Any object that implements IA doesn't have to implement AddOne because there is a default method that would be used.
public class MyClass implements IA { /* No AddOne implementation needed */ }
C# now has this feature in C# 8 (or .Net 5)
C#'s Extension Method
Problems solved:
Ability to add methods to sealed classes.
Ability to add methods to classes from third-party libraries without forcing inheritance.
Ability to add methods to model classes in environments where methods in model classes are not allowed for convention reasons.
The ability for IntelliSense to present these methods to you.
Example: The type string is a sealed class in C#. You cannot inherit from string as it is sealed. But you can add methods you can call from a string.
var a = "mystring";
a.MyExtensionMethed()
Java lacks this feature and would be greatly improved by adding this feature.
Conclusion
There is nothing even similar about Java's default methods and C#'s extension method features. They are completely different and solve completely different problems.
C# extension methods are static and use-site, whereas Java's default methods are virtual and declaration-site.
What I believe you are hoping for is the ability to "monkey-patch" a method into a class you do not control, but Java does not give you that (by design; it was considered and rejected.)
Another benefit of default methods over the C# approach is that they are reflectively discoverable, and in fact from the outside, don't look any different from "regular" interface methods.
One advantage of C#'s extension methods over Java's default methods is that with C#'s reified generics, extension methods are injected into types, not classes, so you can inject a sum() method into List<int>.
Above all, the main philosophical difference between Java's default methods and C#'s extension methods is that C# lets you inject methods into types you do not control (which is surely convenient for developers), whereas Java's extension methods are a first-class part of the API in which they appear (they are declared in the interface, they are reflectively discoverable, etc.) This reflects several design principles; library developers should be able to maintain control of their APIs, and library use should be transparent -- calling method x() on type Y should mean the same thing everywhere.
C# extension methods are just syntactic sugar for static methods that take the extended type as first argument. Java default methods are something completely different. To mimic C# extension methods, just write usual static methods. You will not have the syntatic sugar, however; Java does not have this feature.
Java default methods are real virtual methods. For example, they can be overridden. Consider a class X inheriting from an interface I that declares a default foo() method. If X or any of its super classes declares no own foo() method, then X will get the foo() implementation of I. Now, a subclass Y of X can override X.foo() like a usual method. Thus, default methods are not only syntactic sugar. They are real extensions of the method overriding and inheritance mechanism that cannot be mimicked by other language features.
Default methods even require special VM support, so they are not even a compiler only feature: During class loading, the hierarchy of a class has to be checked to determine which default methods it will inherit. Thus, this decision is made at runtime, not at compile time. The cool thing about it is that you do not have to recompile a class when an interface it inherits gets a new default method: The VM will, at class load time, assign that new method to it.
It is possible to have extension methods with some tricks.
You may give a try to Lombok or XTend. Although extension methods don't come with the out of the box Java implementation, both Lombok and XTend offers a fully working solution.
Lombok is a simple standalone code processing framework, which makes most of the criticized Java specific hassle less painful, including extension methods:
https://projectlombok.org/features/experimental/ExtensionMethod.html
Xtend http://www.eclipse.org/xtend/ goes a few lightyears forward, and implements a language which is a combination of the best parts of modern languages such as Scala on top of Java and Java type system. This allows implementing some classes in Xtend and others in Java within the same project. The Xtend code complies to valid Java code, so no JVM magic happens under the hood. On the other hand, it is a little too much if you have only extension methods missing.
JPropel https://github.com/nicholas22/jpropel-light implements LINQ style extension methods in Java using Lombok. It may worth of a peek :)

Can I always use the Reflection API if the code is going to be obfuscated?

I found that there seem to be 2 general solutions:
don't obfuscate what is referred to through the reflection API [Retroguard, Jobfuscate]
replace Strings in reflection API invocations with the obfuscated name.
Those solutions work only for calls within the same project - client code (in another project) may not use the reflection API to access non-public API methods.
In the case of 2 it also only works when the Reflection API is used with Strings known at compile-time (private methods testing?). In those cases dp4j also offers a solution injecting the reflection code after obfuscation.
Reading Proguard FAQ I wondered if 2 otherwise always worked when it says:
ProGuard automatically handles
constructs like
Class.forName("SomeClass") and
SomeClass.class. The referenced
classes are preserved in the shrinking
phase, and the string arguments are
properly replaced in the obfuscation
phase.
With variable string arguments, it's generally not possible to determine
their possible values.
Q: what does the statement in bold mean? Any examples?
With variable string arguments, it's generally not possible to determine their possible values.
public Class loadIt(String clsName) throws ClassNotFoundException {
return Class.forName(clsName);
}
basically if you pass a non-constant string to Class.forName, there's generally no way for proguard or any obfuscation tool to figure out what class you are talking about, and thus can't automatically adjust the code for you.
The Zelix KlassMaster Java obfuscator can automatically handle all Reflection API calls. It has a function called AutoReflection which uses an "encrypted old name" to "obfuscated name" lookup table.
However, it again can only work for calls within the same obfuscated project.
See http://www.zelix.com/klassmaster/docs/tutorials/autoReflectionTutorial.html.
It means that this:
String className;
if (Math.random() <= 0.5) className = "ca.simpatico.Foo";
else className = "ca.simpatico.Bar";
Class cl = Class.forName(className);
Won't work after obfuscation. ProGuard doesn't do a deep enough dataflow analysis to see that the class name which gets loaded came from those two string literals.
Really, your only plausible option is to decide which classes, interfaces, and methods should be accessible through reflection, and then not obfuscate those. You're effectively defining a strange kind of API to clients - one which will only be accessed reflectively.

What's the conception behind: Type - Element - Mirror

I'm working with Java 6's annotation processing, i.e. what can be found within javax.annotation.processing (not Java 5's APT).
I wonder what the conceptional difference between the various Element, Type, and Mirror classes is. As I don't really understand this, it's hard to efficiently program an annotation processor. There are various methods that 'convert' between these notions but I'm not really sure what I'm doing when using them.
So, for example, let me have an instance of AnnotationMirror.
When I call getAnnotationType() I get an instance of DeclaredType (which implements TypeMirror for whatever reason).
Then I can call asElement() on this one and obtain an instance of Element.
What has happened?
There is indeed on overlap between these concepts.
Element models the static structure of the program, ie packages, classes, methods and variables. Just think of all you see in the package explorer of Eclipse.
Type models the statically defined type constraints of the program, ie types, generic type parameters, generic type wildcards. Just think of everything that is part of Java's type declarations.
Mirror is an alternative concept to reflection by Gilad Bracha and Dave Ungar initially developed for Self, a prototype-based Smalltalk dialect. The basic idea is to separate queries about the structure of code (and also runtime manipulation of the structure, alas not available in Java) from the domain objects. So to query an object about its methods, instead of calling #getClass you would ask the system for a mirror through which you can see the reflection of the object. Thanks to that separation you can also mirror on classes that are not loaded (as is the case during annotation processing) or even classes in a remote image. For example V8 (Google's Javascript engine) uses mirrors for debugging Javascript code that runs in another object space.
This paper may help understanding the design of Java 6 annotation processing:
Gilad Bracha and David Ungar. Mirrors:
Design Principles for Meta-level
Facilities of Object-Oriented
Programming Languages. In Proc. of
the ACM Conf. on Object-Oriented
Programming, Systems, Languages and
Applications, October 2004.
The object of type javax.lang.model.element.AnnotationMirror represents an annotation in your code.
The declared type represents the annotation class.
Its element is the generic class (see http://java.sun.com/javase/6/docs/api/javax/lang/model/element/TypeElement.html for more information on that matter). The element might be the generic version of a class, like List, where as the declared type is the parametrized version, for instance List<String>. However I'm not sure it is possible to have annotations classes use generics and thus the distinction might be irrelevant in that context.
For instance lets say you have the following JUnit4 method:
#Test(expected = MyException.class)
public void myTest() {
// do some tests on some class...
}
The AnnotationMirror represents #Test(expected = NullPointerException.class). The declared type is the org.junit.Test class. The element is more or less the same as there are no generics involved.

Categories

Resources