How to use Scala implicit class in Java - java

I have a Scala Implicit class from RecordService API, which i wanted to use in Java file.
package object spark {
implicit class RecordServiceContext(ctx: SparkContext) {
def recordServiceTextFile(path: String) : RDD[String] = {
new RecordServiceRDD(ctx).setPath(path)
.map(v => v(0).asInstanceOf[Text].toString)
}
}
}
Now i am trying to import this in a Java file using below import.
import com.cloudera.recordservice.spark.*;
But i am not able to use recordServiceTextFile("path") from sparkContext.
In Scala the import is little different and its working.

Here is simple definition of implicit class in package object
package object spark {
implicit class Ext(param: Int) {
def a = param + 1
}
}
and here is how you can use it from java
public class Test {
public static void main(String[] args) {
spark.package$.MODULE$.Ext(123).a();
}
}
so you can basically use RecordServiceContext as a method that wraps your SparkContext and adds an extra method that you can call. That is optimization for implicit classes.
That would be something like this:
SparkContext c = ???
RDD<String> rdd = com.cloudera.recordservice.spark.package$.MODULE$.RecordServiceContext(c)
.recordServiceTextFile("asdf");

A package object spark is compiled to a class package in the package spark. The implicit class RecordServiceContext will get compiled to a static method RecordServiceContext (that's scala's implicit def) in package and a class package$RecordServiceContext.
So the following code should do it:
import com.cloudera.recordservice.spark.*;
//some code
RDD<String> rdd = package.RecordServiceContext(myContext).recordServiceTextFile(pathToFile);
//some code
But package is probably a reserved keyword, and Java has no way of escaping them as far as I know. So you'll have to do some reflection to invoke the RecordServiceContext method.

SparkContext ctx = ...
RecordServiceContext rsct = new RecordServiceContext(ctx)
recordServiceTextFile("/your_path")

This should do it.
String s = new spark.RecordServiceContext("safa").recordServiceTextFile("dsf");
I changed the signatures though.
My Scala class looks like this ,
object spark {
implicit class RecordServiceContext(ctx: String) {
def recordServiceTextFile(path: String) : String = {
"test"
}
}
}
My java class looks like this,
public class TestScalaCall {
public static void main(String args[]){
String s = new spark.RecordServiceContext("safa").recordServiceTextFile("dsf");
}
}
Edit ---
So a quick look of the Scala change requests shows us this.
They are actually working on making a class defined under a package object behave the same way as defining it inside a regular package. But that is targeted for the yet to be release 2.12 .
So the recommendation they are giving is keep only absolutely necessary classes/objects that do not needs any external interaction inside package objects. Otherwise keep them under regular packages.
So for now you need to not use the package object construct.
Also , a point worth pondering "Does it really make sense to define something that is accessible on the outside inside a package object ? "

Related

Using a java class inside another class without it's java file being actually present

I am writing a backend where the users can write some code inside a pre-written class like so,
import java.utils.*;
public class SomeClass{
public int fun(){
// some code written by the user.
}
}
Note : This SomeClass has no .java file in my project and loaded using the String code. The value of string being the above code itself.
I am creating this class object using GroovyClassLoader like so,
try (GroovyClassLoader gcl = new GroovyClassLoader()) {
// code is a String. The value of this code string is the above code.
Class<?> loadedClass = gcl.parseClass(code);
Class<?> add = gcl.parseClass(addClass);
// using this object
}
Now if I have another class or classes like so,
import java.utils.*;
public class Addition{
public int add(int a, int b){
return a+b;
}
}
Note:This is also not present as a .java file in my code base, it is present as a String variable as above.
I can use the GroovyClassLoader to load both the class but how can is use this Addition class inside my SomeClass class, like this,
import java.utils.*;
// somehow importing Addition class
public class SomeClass{
public int fun(){
Addition addition = new Addition();
return addition.add(2, 3);
}
}
As clearly mentioned above none of these files are actually present as .java files in my project and thus there is no package for any of these classes, so is there anyway in which SomeClass can import and use Addition. If not then is there anyway this can be achieved.
Note : Another example of my problem can be some online coding sites like Leetcode for example, there we only write the main code (in my case SomeClass) and the boilerplate code (like initialising the arrays, variable and taking input and output, in my case the Addition class) is injected to my main code by LeetCode itself. So I want to achieve something like this.

How to implement an Objective-C in Swift without defining a new class

In Java we can declare an interface and then create a new object which conforms to that interface very simply.
public interface Executer {
void execute();
}
Executer executer = new Executer() {
#Override
public void execute() {
System.out.println("we did it!");
}
}
Now I want to do the same thing, by defining a protocol in Objective-C and implementing it in Swift.
#protocol Executer <NSObject>
- (void)execute;
#end
How do I implement this protocol in my Swift code like in the Java example?
Swift does not have a direct equivalent of Java's anonymous classes.
You don't say why you want to do this, e.g. what is it about this construct that makes you want it over what Swift does provide? Given that we'll just show two alternatives, maybe one will suit you.
Swift supports nested types, so you can declare a local type within your class and instantiate it. For example:
#objc public class Explore : NSObject
{
#objc private class notAnAnonButPrivateClass : NSObject, Executer
{
func execute() -> Void
{
print("we did it!")
}
}
var executer : Executer = notAnAnonButPrivateClass()
This declares the private class and then an instance variable initialised to an instantiation of it.
If you want to be able to provide the implementation of execute() inline with the declaration then you can do that using a Swift closure (equivalent to block in Objective-C) and use the trailing closure syntax to pretty it up a bit:
#objc private class notAnAnonButPrivateClass : NSObject, Executer
{
let executeImpl : () -> Void
init(_ theImpl : #escaping () -> Void)
{
executeImpl = theImpl
}
func execute() -> Void
{
executeImpl()
}
}
var executer : Executer = notAnAnonButPrivateClass() {
print("we did it again!")
}
In this version the private class' init takes a closure to use for the body of execute() and that closure is written directly in line in the instance variable initialisation.
This version also differs semantically from the first as the closure may capture values and variables from its enclosing scope.
So to summarise: you don't get anon classes, you must give them a name (but can use something more sensible than notAnAnonButPrivateClass!) and that name does not "leak" into the rest of your code (the private bit); and you can if you (really) wish provide the method body at the point of instantiation. Maybe one of these will suit you.
HTH

Accessing Kotlin extension functions from Java

Is it possible to access extension functions from Java code?
I defined the extension function in a Kotlin file.
package com.test.extensions
import com.test.model.MyModel
/**
*
*/
public fun MyModel.bar(): Int {
return this.name.length()
}
Where MyModel is a (generated) java class.
Now, I wanted to access it in my normal java code:
MyModel model = new MyModel();
model.bar();
However, that doesn't work. The IDE won't recognize the bar() method and compilation fails.
What does work is using with a static function from kotlin:
public fun bar(): Int {
return 2*2
}
by using import com.test.extensions.ExtensionsPackage so my IDE seems to be configured correctly.
I searched through the whole Java-interop file from the kotlin docs and also googled a lot, but I couldn't find it.
What am I doing wrong? Is this even possible?
All Kotlin functions declared in a file will be compiled by default to static methods in a class within the same package and with a name derived from the Kotlin source file (First letter capitalized and ".kt" extension replaced with the "Kt" suffix). Methods generated for extension functions will have an additional first parameter with the extension function receiver type.
Applying it to the original question, Java compiler will see Kotlin source file with the name example.kt
package com.test.extensions
public fun MyModel.bar(): Int { /* actual code */ }
as if the following Java class was declared
package com.test.extensions
class ExampleKt {
public static int bar(MyModel receiver) { /* actual code */ }
}
As nothing happens with the extended class from the Java point of view, you can't just use dot-syntax to access such methods. But they are still callable as normal Java static methods:
import com.test.extensions.ExampleKt;
MyModel model = new MyModel();
ExampleKt.bar(model);
Static import can be used for ExampleKt class:
import static com.test.extensions.ExampleKt.*;
MyModel model = new MyModel();
bar(model);
Kotlin top-level extension function are compiled as Java static methods.
Given Kotlin file Extensions.kt in package foo.bar containing:
fun String.bar(): Int {
...
}
The equivalent Java code would be:
package foo.bar;
class ExtensionsKt {
public static int bar(String receiver) {
...
}
}
Unless, that is, Extensions.kt contained the line
#file:JvmName("DemoUtils")
In which case the Java static class would be named DemoUtils
In Kotlin, extension methods can be declared in other ways. (For example, as a member function or as an extension of a companion object.)
With newer KotlinEx, you can directly call extension in java
ExtensionFileName.foo(field1...)
Basically, what it does is, it makes the receiver as first arguement and other arguments remain being at the same place
So For eg.
You have extension(in file Extension.kt)
Context.showToast(message:String){
...
}
In Java, you call it as
ExtensionKt.showToast(context, message);
I have a Kotlin file called NumberFormatting.kt that has the following function
fun Double.formattedFuelAmountString(): String? {
val format = NumberFormat.getNumberInstance()
format.minimumFractionDigits = 2
format.maximumFractionDigits = 2
val string = format.format(this)
return string
}
In java I simple access it over the file NumberFormattingKt in the following way after the required import import ....extensions.NumberFormattingKt;
String literString = NumberFormattingKt.formattedFuelAmountString(item.getAmount());
You can always see the actual Java code which is getting generated from your Kotlin code by going to Tools > Kotlin > Show Kotlin Bytecode, then clicking Decompile. This can help you tremendously. In your case the Java code will look like this if you have MyModelExtensions.kt
public final class MyModelExtensionsKt {
public static final int bar(#NotNull MyModel $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
return $receiver.getName().length();
}
}
you can improve over this by using #JvmName on the file containing bar:
#file:JvmName("MyModels")
package io.sspinc.datahub.transformation
public fun MyModel.bar(): Int {
return this.name.length
}
and it will result in this code:
public final class MyModels {
public static final int bar(#NotNull MyModel $receiver) {
Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
return $receiver.getName().length();
}
}
Using MyModels is in line with what Effective Java suggests for utility classes. You can also rename your method like this:
public fun MyModel.extractBar(): Int {
return this.name.length
}
then from the Java side it will look idiomatic:
MyModels.extractBar(model);
It works for me:
Kotlin
Java code
My project is an old android project created with Java; now I created the first kotlin file and added String extensions
fun String.isNotNullOrEmpty(): Boolean {... }
and I could call it from java file using:
StringUtilsKt.isNotNullOrEmpty(thestring).
My kotlin file name is StringUtils
The other answers here cover the case of calling an extension function located at the top level of a Kotlin package file.
However, my case was that I needed to call an Extension function located inside a Class. Specifically, I was dealing with an Object.
The solution is incredibly simple.
All you have to do is annotate your extension function as #JvmStatic, and voila! Your Java code will be able to access it and use it.
When you extend a class like this:
fun String.concatenatedLength(str: String): Int {
return (this.length + str.length)
}
fun f() {
var len = "one string".concatenatedLength("another string")
println(len)
}
It will compile to this:
import kotlin.jvm.internal.Intrinsics;
import org.jetbrains.annotations.NotNull;
public final class ExampleKt {
public static final int concatenatedLength(#NotNull String $receiver, #NotNull String str) {
Intrinsics.checkParameterIsNotNull((Object) $receiver, (String) "$receiver");
Intrinsics.checkParameterIsNotNull((Object) str, (String) "str");
return $receiver.length() + str.length();
}
public static final void f() {
int len = ExampleKt.concatenatedLength("one string", "another string");
System.out.println(len);
}
}
There are more examples here.
As far as I can tell this isn't possible. From my reading of the extensions docs, it appears that
public fun MyModel.bar(): Int {
return this.name.length()
}
creates a new method with the signature
public static int MyModelBar(MyModel obj) {
return obj.name.length();
}
Then, Kotlin maps that function to calls of the form myModel.bar(), where if bar() isn't found in the MyModel class it looks for static methods matching the signature and naming scheme it outputs. Note that this is just an assumption from their statements about extensions being statically imported and not overriding defined methods. I haven't gotten far enough in their source to know for sure.
So, assuming the above is true there's no way for Kotlin extensions to be called from plain old java code, as the compiler will just see an unknown method being called on an object and error out.

Is it possible to change buggy class in a closed source library that was not built to support dependency injection?

Say I am using a closed source java library with a known buggy class, say BuggyClass and this class is hardcoded throughout the rest of the library. So I would imagine that the java library looks something like this:
public class BuggyClass {
public T buggyMethod (...) {
// Buggy code here
}
}
with several other classes in the library that make use of this class:
public class Example {
private BuggyClass = new BuggyClass(); // No dependency injection possible
public Example (/* No way to pass in my own subclass of BuggyClass*/) {
// ...
}
}
etc...
Is there any hack, or workaround, possibly using the class loader so that I could subclass BuggyClass and get Example (and every other class in the library that has BuggyClass hardcoded in) to use my subclass?
You can't do a subclass, no, but you can write your own BuggyClass entirely and make sure it appears earlier in the classpath than the real one. I don't think it's documented, but the default classloader seems to typically use the first matching class it finds.
But obviously this is a Really Bad Option, so you want to exhaust every other avenue before trying to solve temporarily work around the underlying problem this way.
Example: Suppose we have this:
// The "buggy" class
package somepackage;
public class BuggyClass {
public String someMethod() {
return "I'm in the buggy class";
}
}
and this:
// Uses the "buggy" class
package somepackage;
public class BuggyClassUser {
public String useBuggyClass() {
BuggyClass c = new BuggyClass();
return c.someMethod();
}
}
compiled and the classes in buggy.jar. Then we have this test class:
import somepackage.*;
public class Test {
public static final void main(String[] args) {
BuggyClassUser u = new BuggyClassUser();
System.out.println(u.useBuggyClass());
}
}
If we run that (*nix format classpath):
java -cp .:buggy.jar Test
...we see
I'm in the buggy class
But if we create a somepackage directory and put this in it:
package somepackage;
public class BuggyClass {
public String someMethod() {
return "I'm in the fixed class"; // <== Difference here
}
}
...and compile that, since we have that in our classpath in front of the jar, this command:
java -cp .:buggy.jar Test
...now gives us this:
I'm in the fixed class
Again, this is very, very much a workaround, not a solution.

Java function (method) available everywhere (global)

I've recently (4 days ago) started programming in JAVA. I have some overall programming experience from C++ and PHP. My question is: can we implement a function in JAVA, that is available in all classes? I'm thinking of some global logging function, that I need to call in several places (log events, errors, etc.).
Imagine I have two classes, A and B. I need to call logging function in both of them, but I don't want to copy whole function body (awful thing I believe), and I want to call it strict (without creating another class, instantiating it, and then calling from the instance), like logEvent(someVariable). So I should use an abstract class C, which A and B will extend, BUT they are already an extension of other class (built-in). Since multiple inheritance isn't allowed (is it?), I need to do some trick. Singleton is not pleasing me too. In PHP or C++ I would just create separate file with function body and then include it.
Here is how I want to use it:
public class A extends SomeClass {
String error = "Error from class A";
logEvent(error);
}
public class B extends SomeOtherClass {
String error = "Error from class B";
logEvent(error);
}
Put a static method in any class (it could be a utils class, or whatever), then call it like this: ClassName.functionName()
Static methods belong to the class, not instances of the class, so you don't need to instantiate the class to access the method
But everything in Java has to be in a class, so you can't access it without the class name.
You should use static method:
package xxx;
public class Util{
public static void logEvent(String error){
...
}
}
and import static:
import static xxx.Util.*;
public class A extends SomeClass {
String error = "Error from class A";
logEvent(error);
}
You may use static method.
Define a class with a static method:
public class Util{
public static void logEvent(String error){
...
}
}
Then, you can use static metod like this way:
public class A extends SomeClass {
String error = "Error from class A";
Util.logEvent(error);
}
you may take a look here to learn more about static method, http://www.leepoint.net/notes-java/flow/methods/50static-methods.html

Categories