I need to create some extension methods in my Java code. I've read some posts here in SO and people suggest XTend or Scala in order to achieve this.
Now, my question would be.. if i write kind of an Adapter layer in Scala (adding there my extension methods) and then using that project as a dependency for my own Java project, are those extended methods available for me to use, or they are defined just for the 'scope of Scala project' and then the JVM output cannot provide those new methods to the other project using it?
EDIT:
What i need to do is to extend a full hierarchy of classes in a given library and give some new functionality. As for Java's first approach I should extend every class in that hierarchy creating my own hierarchy of extended classes adding the new method there. I would like to avoid this and give the final user the sense of native functionality in the original hierarchy.
Regards.
As mentioned above in the comments, it is very close to C# but not exactly there because of the type erasure. For example, this works fine:
object myLibExtensions {
implicit class TypeXExtension( val obj: TypeX ) extends AnyRef {
def myCustomFunction( a: String ): String = {
obj.someMethod(a)
}
}
}
It will act somewhat similar to C# extension methods, i.e. create static method wrappers in reasonable cases (but not always).
The only thing I am missing in Scala is that you can't (or at least I couldn't figure out how to) return the values of the types being extended. For example, assume I want to have something like an extension method "withMeta" that works as follows:
class TypeY extends TypeX { def methodOfY(...) ...}
var y: TypeY = ....
y.withMeta(...).methodOfY(...)
The following didn't work for me:
object myLibExtensions {
private val something = ....
implicit class Extension[T<:TypeX]( val obj: T ) extends AnyRef {
def withMeta( meta: Meta[T] ): T = {
something.associateMeta(obj,meta)
val
}
}
}
... because T is being erased to TypeX. So effectively you will have to write extensions for all specific leaf classes of the hierarchy in this case, which is sad.
Related
I am exploring and actively using generics in production with Kotlin.
Kotlin + generics is a big puzzle for me, so maybe you can explain and help me understand how it works here, compared to Java.
I have class AbstracApiClient (not really abstract)
class AbstracApiClient {
open protected fun makeRequest(requestBuilder: AbstractRequestBuilder) {
// ...
}
}
AbstractRequestBuilder (not really abstract):
open class AbstractRequestBuilder {
...
}
ConcreteApiClient that inherits AbstractApiClient that should override makeRequest with ConcreteRequestBuilder inherited from AbstractRequestBuilder:
class ConcreteApiClient: AbstractApiClient() {
protected override fun makeRequest(requestBuilder: ConcreteRequestBuilder) {
// ...
}
}
class ConcreteRequestBuilder: AbstractRequestBuilder()
As I would have more concrete API clients. I would like to make an abstraction that I can pass inherited concrete requests builders and override `make requests method.
I tried using it as it is but wouldn't work
I tried this notation protected open fun <R: ApiRequestBuilder> make request(request builder: R) but it won't match overriding function which I want it to be: protected override fun make request(request builder: ConcreteRequestBuilder)
What other options do I have? Am I missing something here?
Note: I cannot use interface or abstract classes in this scenario, so ideally I would like to find a way with inheritance and functions overriding.
You can't override a method with more specific argument types, because it breaks Liskov's substitution principle:
val client: AbstractApiClient = ConcreteApiClient()
client.makeRequest(AbstractRequestBuilder())
As you can see above, the ConreteApiClient implementation has to be able to handle all possible inputs of the parent class, because it could be accessed through the parent class's API.
To do what you want, you need to restrict the parent class itself via generics:
open class AbstractApiClient<R : AbstractRequestBuilder> {
open protected fun makeRequest(requestBuilder: R) {
// ...
}
}
class ConcreteApiClient: AbstractApiClient<ConcreteRequestBuilder>() {
protected override fun makeRequest(requestBuilder: ConcreteRequestBuilder) {
// ...
}
}
This way, any instance of AbstractApiClient<R> has to show which type of request builder it accepts (in the type argument). It prevents the above issue because now the parent type also carries information:
// doesn't compile
val client: AbstractApiClient<AbstractRequestBuilder> = ConcreteApiClient()
// this compiles
val client: AbstractApiClient<ConcreteRequestBuilder> = ConcreteApiClient()
I tried this notation protected open fun <R: ApiRequestBuilder> make request(request builder: R)
Now regarding this attempt, it doesn't work because if you make the method generic (not the class) it means every implementation of the method has to handle all kinds of R (NOT one R per implementation). Putting the generic on the class allows to specify the generic argument once per instance of the class.
Why accessing constants defined in java interface from kotlin interface is not allowed or at least I am not able to access it. Is there any other way?
(Yes,I know The constant interface pattern is a poor use of interfaces from Effective Java book)
Following code (java) compiles
// ==== JSubsystem.java ====
public interface JSubsystem {
String IRIS = "IRIS";
String TCS = "TCS";
// ...
}
// ==== JComponentType.java ====
public interface JComponentType {
String HCD = "HCD";
String Assembly = "Assembly";
// ...
}
interface Demo extends JSubsystem {
default void foo() {
System.out.println(IRIS);
}
}
But in the following kotlin interface which extends from java, IRIS|TCS|HCD is not accessible
// ==== AllModels.kt ====
interface AllModels : JSubsystem, JComponentType {
fun foo() = println(IRIS)
}
More context on why we ended up at this situation:
We have a large scala codebase, all the models provide java and scala access.
Now we have scripting requirement for 1-5% of our users where we have utilised kotlin's scripting (.kts), dsl, coroutines and suspension features
We have provided script construct inside which users will have access to complete DSL and all the models.
We do not want users to explicitly import models from different files and we do not want to repeat defining models again in kotlin.
One of the solution we thought could work in this case is having java models (these are simple delegations to scala models) in interface and then have one interface at kotlin side which extends from all these java model interfaces and then script can be receiver of this interface - AllModels
You need to specify interface explicitly:
fun foo() = println(JSubsystem.IRIS)
Or you can import constant explicitly:
import your.package.name.JSubsystem.IRIS
You can customize your script environment as described in https://github.com/Kotlin/KEEP/blob/master/proposals/scripting-support.md, in particular you can add imports which will be automatically available with defaultImports.
This example in the Kotlin discussion forum should be helpful:
First, you need to create a script definition - a separate jar that describes your script “template”, e.g. similar to the https://github.com/JetBrains/kotlin/tree/master/libraries/tools/kotlin-main-kts
Your definition may look something like:
#KotlinScript(fileExtension = "custom.ext", compilationConfiguration = ScriptConfiguration::class)
abstract class MyScript(val bindings: Map<String, Any?>) {
val ortResult = bindings["ortResult"] as OrtResult
val evalErrors = mutableListOf<OrtIssue>()
}
object ScriptConfiguration : ScriptCompilationConfiguration(
{
defaultImports("com.here.ort.model.*", "java.util.*")
ide {
acceptedLocations(ScriptAcceptedLocation.Everywhere)
}
})
It is a good idea to have a dedicated extension for your scripts (“custom.ext” in the example above), since IDE distinguish scripts by the extension.
Then you’ll need to create your own JSR-223 factory the same way as here - https://github.com/JetBrains/kotlin/blob/master/libraries/tools/kotlin-script-util/src/main/kotlin/org/jetbrains/kotlin/script/jsr223/KotlinJsr223ScriptEngineFactoryExamples.kt#L28, but use your script definition (MyScript) in place of KotlinStandardJsr223ScriptTemplate. You probably can do it in the same jar. And you need to register it in the services folder, of course.
You’ll still need a postface part in your evaluator though, but it seems not relevant to the IDE.
Then finally you need to supply Intellij with the definition. The simplest ad-hoc way to do it is to specify the FQN of your definition class along with the classpath needed to load it in the kotlin compiler settings -> “Kotlin scripting” in Intellij.
I'm new to annotation processing and code generation. I want to find out how can I perform such operation like appending new method to existing class. Here is an example of what I want to do:
Assume that we have a class with with custom annotations like this one:
class SourceClass {
#CustomAnnotation
fun annotatedFun1(vararg argument: Any) {
//Do something
}
#CustomAnnotation
fun annotatedFun2(vararg argument: Any) {
//Do something
}
fun someOtherFun() {
//Do something
}
}
And the result I want to get - extended copy of that class:
class ResultClass {
fun hasFunWithName(name: String): Boolean {
return (name in arrayOf("annotatedFun1", "annotatedFun2"))
}
fun callFunByName(name: String, vararg arguments: Any) {
when (name) {
"annotatedFun1" -> annotatedFun1(*arguments)
"annotatedFun2" -> annotatedFun2(*arguments)
}
}
fun annotatedFun1(vararg argument: Any) {
//Do something
}
fun annotatedFun2(vararg argument: Any) {
//Do something
}
fun someOtherFun() {
//Do something
}
}
I've already found out how to create annotation processor. I'm looking for a method to save all existing fields, properties and methods in source class and to append a few more methods to it.
If it is possible to modify class without creating new one - it would be perfect, but in all tutorials only new classes are created and I didn't find any example where all contents of source class are being copied to another one.
Please, do not advise to use reflection. I need this for android and so reflection is not the option cause of resources cost. I'm looking for compile-time solution.
It is required for custom script language implemented in app and should be used to simplify wrapper classes structure. When this job is done directly in code - it looks awful when such method count exceeds 20 per class.
Here is a good example of Java Annotation Processing I recently worked with.
It's an implementation of #Immutable annotation.
Check out ByteBuddy or Kotlin Poet to understand how additional code generation works.
For Kotlin you do almost the same, check this manual for Kotlin-specific steps.
With Kotlin, you can use extension functions and that is the recommended way of adding new functionality to existing classes that you don't control. https://kotlinlang.org/docs/reference/extensions.html
You may be abel to follow the pattern used by Project Lombok. See How does lombok work? or the source code for details.
Another option would be to write a new class that extends your source class:
class ResultClass : SourceClass {
fun hasFunWithName(name: String): Boolean {
return (name in arrayOf("annotatedFun1", "annotatedFun2"))
}
fun callFunByName(name: String, vararg arguments: Any) {
when (name) {
"annotatedFun1" -> annotatedFun1(*arguments)
"annotatedFun2" -> annotatedFun2(*arguments)
}
}
}
Or perhaps use composition instead and implemnent cover methods for all the public methods in SourceClass.
If you are not tied to doing this using annotation processing, you could use a separate piece of custom code to process the source code files before compiling. Maybe use a regular expression like /#CustomAnnotation\s+.*fun (\w+)\s*\(([^)]*)\)/gm (Test on Regex101) to find the annotated methods.
If I understood the requirement correctly, the goal is to implement something like described below.
You have a source file C.java that defines the class C like this:
public final class C
{
#Getter
#Setter
private int m_IntValue;
#Getter
#Constructor
private final String m_Text;
}
And now you want to know how to write an annotation processor that jumps in during compilation and modifies the source from C.java that the compiler sees to something like this:
public final class C
{
private int m_IntValue;
public final int getIntValue() { return m_IntValue; }
public final void setIntValue( final int intValue ) { m_IntValue = intValue; }
private final String m_Text;
public final String getText() { return m_Text; }
public C( final String text ) { m_Text = text; }
}
The bad news is, that this is not possible … not with an annotation processor, not for Java 15.
For Java 8 there was a way, using some internal classes with reflection to convince the AP to manipulate the already loaded source code in some way and let the compiler compile it a second time. Unfortunately, it failed more often than it worked …
Currently, an annotation processor can only create a new (in the sense of additional) source file. So one solution could be to extend the class (of course, that would not work for the sample class C above, because the class itself is final and all the attributes are private …
So writing a pre-processor would be another solution; you do not have a file C.java on your hard drive, but one named C.myjava that will be used by that preprocessor to generate C.java, and that in turn is used by the compiler. But that is not done by an annotation processor, but it may be possible to abuse it in that way.
You can also play around with the byte code that was generated by the compiler and add the missing (or additional) functionality there. But that would be really far away from annotation processing …
As a summary: today (as of Java 15), an annotation processor does not allow the manipulation of existing source code (you cannot even exclude some source from being compiled); you can only generate additional source files with an annotation processor.
I have an application which should produce cars and operate with them. Car object creation is a complex process so I need a factory for each type of car. Also I want users to be able to provide their own type of cars and factories which produce them. These car types and factories should be plugged to my application as jars (probably there is a better way than jars but I don't see it).
I've come to an idea of making a common CarFactory which accepts the name of the car ("mercedes", "bmw", "nissan", etc) as an argument. CarFactory has a map where each name is mapped to its own factory class. The code looks something like this (sorry I can't provide a working copy because I'm still evaluating it and don't have a version which compiles without errors)
import scala.collection.mutable.Map
class CarFactory {
var knownCarTypes = Map[String, Class[Factory]]()
def create(carType: String) = knownCarTypes.get(carType) match {
case Some(factoryClass) => Some(factoryClass.getMethod("create").invoke(null).asInstanceOf[Car])
case None => None
}
}
}
The knownCarTypes is mutable because I want user factories to register on this map providing what type of car they are responsible for and what is the name of the factory class. So from a user class it looks like this
class Mercedes extends Car
object MercedesFactory extends Factory {
def register() {
CarFactory.knownCarTypes("mercedes") = getClass
}
def create() = new Mercedes()
}
And here is my question. I don't know how to trigger the register() method of a user factory. Is it possible? Is there a better solution than my approach?
I thought about making common trait for factories, find all loaded classes implementing the trait and trigger method via reflection. But it looks quite complex. I hope some design pattern or OOP trick can be used here. What do you think?
Thanks!
If I understand your question correctly, all you have to do is call register from the object's "body":
object MercedesFactory extends Factory {
def register() {
CarFactory.knownCarTypes("mercedes") = getClass
}
register
def create() = new Mercedes()
}
Finally I got it working via reflection. I iterated over all jars on specified path, found all classes implementing my com.example.Factory trait and triggered their register() method. For jars inspection I used Clapper ClassFinder and for invoking object method I followed Thomas Jung advice. Here is the final code
import org.apache.commons.io.FileUtils
import org.clapper.classutil.{ClassFinder, ClassInfo}
import scala.collection.JavaConverters._
def triggerFactories() {
val jars = FileUtils.iterateFiles(new File("lib"), Array[String]("jar"), true).asScala.toList
val classes = ClassFinder(jars).getClasses
val factories = ClassFinder.concreteSubclasses("com.example.Factory", classes)
factories.foreach { (factory: ClassInfo) =>
companion[Factory](factory.name).register()
}
}
def companion[T](name: String)(implicit man: Manifest[T]): T =
Class.forName(name).getField("MODULE$").get(man.erasure).asInstanceOf[T]
It's worked for me. It looks tricky but I hope it won't break anything in my application in future. Please post if there is better approach, I'll reaccept the answer.
I am writing client code in Scala that needs to interface with a framework in Java. The framework is responsible for creating object instances of classes specified via an API, which it does using reflection. For example:
public class ReflectionUtil {
public static <T> T newInstance(Class<T> aClass) {
T result;
try {
Constructor<T> meth = aClass.getDeclaredConstructor(new Class[]{});
meth.setAccessible(true);
result = meth.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
return result;
}
}
The classes of the object instances I want to create are implemented in Scala and are paramerterised on a type that has a context bound on it. For example:
class OrderedValue[A](var value: A)(implicit ord: Ordering[A]) {
def get: A = value
def set(x: A) = { value = x }
def cmp(that: OrderedValue[A]): Int = ord.compare(this.value, that.value)
}
I run into a problem when I pass this class to the Java framework to construct new instances as the framework makes the assumption that the class will have a zero-argument constructor available. For example, the following code will result in a NoSuchMethodException from within newInstance:
def main(args: Array[String]) {
val a: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])
val b: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])
a.set(3)
b.set(5)
println(a.cmp(b))
}
An attempt at resolving this issue is to add a zero-argument constructor to OrderedValue however there is no reasonable value for the implicit parameter ord. Setting it to null will result in a NullPointerException within cmp:
def this() = this(null.asInstanceOf[A])(null.asInstanceOf[Ordering[A]])
Another approach is to subclass a particular concrete value of OrderedValue. For example:
class OrderedIntValue(val v: Int) extends OrderedValue[Int](v) {
def this() = this(null.asInstanceOf[Int])
}
val a: OrderedValue[Int] = ReflectionUtil.newInstance(classOf[OrderedValue[Int]])
This will work but is not ideal as it is not always convenient or possible to know the concrete type of OrderedValue. For example, newInstance may be called within a scope that is also parameterised on a type (i.e. we don't know that it's specifically an Int).
So my question is: given that context bounds (i.e. type classes) are a very useful, and now commonly used, feature within Scala, and given I can not change the internals of the Java framework that I am interfacing with, has anyone encountered or developed an approach that can make this all work?
Implicit arguments are filled in by the Scala compiler at the compile time. If you want to instantiate classes using reflection you will have to specify those arguments manually. There is just no way around it. So you can either have context bounds or no-argument constructors.
I found that the easiest way of calling Scala code from Java is to write an intermediate Scala layer with the Scala equivalent of POJOs. No implicits, no closures in signatures, no Companion object, no complicated type inference, etc. (of course, you can use these internally). I also try to replace most scala Collections types in signatures with java.util Collections.
Yes, it is ugly, tedious and not very flexible, but at least it removes a lot of syntax nightmare from the Java side.