public class member in scala class not accessible in java class - java

I'm learning scala, and to practice, I have started to convert some of my existing java classes into scala, so I can also learn about scala-java inter-op. Following is my project setup:
Scala class :
#Entity
class DemoBeanScala{
#Id
#GeneratedValue(strategy=GenerationType.AUTO)
#BeanProperty
var Id: Long= _
#BeanProperty
var str: String= _
#BeanProperty
var num: Int = _
#BeanProperty
var d:Double = _
def testFunc(printText: () => Unit){
printText()
}
val pr = () => {
println("functional programming test")
}
}
Java class(extract):
#RequestMapping("/demo")
public DemoBeanScala demo(#RequestParam(value="id") Long Id, #RequestParam(value="str") String str, #RequestParam(value="num") int num, #RequestParam(value="d") double d)
{
DemoBeanScala dbs = new DemoBeanScala();
dbs.setId(123456);
dbs.setStr("sample text");
dbs.setNum(1);
dbs.setD(2.1);
dbs.testFunc(dbs.pr);
return dbs;
}
From what I have learnt, pr in DemoBeanScala class should be accessible in my java class, since no modifier is declared before it. But, after maven compilation(using scala:compile) and running java code, I'm getting an error saying that pr is private in DemoBeanScala class. What am I doing wrong?

If you look at your compiled class in javap, you will see somethign like this :
public class DemoBeanScala {
private final scala.Function0<scala.runtime.BoxedUnit> pr;
public scala.Function0<scala.runtime.BoxedUnit> pr();
// And some other stuff...
}
You will notice two important difference with Java :
Scala respects the uniform access principle, so there is no difference between calling a method without a parameter list or accessing a property. To make that work, the scala compiler will generate a public accessor method and a private field to represent a public property.
Java doesn't have methods without a parameter list: they always have at least an empty parameter list.
So, from Java, you need to access the pr property with dbs.pr(), not dbs.pr (or generate a Java-style getter with #BeanProperty, as you did for your other properties, and access it as dbs.getPr()).

When you add #BeanProperty that particular property is not visible in java class, only the generated public setters and getters are available or you may access scala like setter (pr_$eq()) and getter (pr()).
I could not find a proper reference, but the following links may helpful for you, they are not directly related to this question, but they will help you understanding.
Scala: Can I declare a public field that will not generate getters and setters when compiled?
https://issues.scala-lang.org/browse/SI-4481

Related

How to use setter for this Kotlin class property?

I have the following class coded in Kotlin:
class MyClass {
var color: String = ""
var action: String = ""
val owners = Array(1) {Owner()}
class Owner {
var userId: String = ""
var userName: String = ""
}
}
...and I'm accessing it Java:
MyClass myObject = new MyClass();
myObject.setColor("blue");
myObject.setAction("throw");
...and I'd like to be able to set the owner. I'm not sure how, though. If it were an object that was coded in Java with public members, I'd just do something like:
myObject.owners[0].userId = "001";
myObject.owners[0].userName = "Freddy"
Since the object was coded in Kotlin, I need to user a setter in Java.
How do I set the properties in the first element of an array with a setter?
For each Kotlin property foo, you can call its getter in Java as getFoo() and, if the property is mutable, the setter as setFoo(value).
See: Calling Kotlin from Java — Properties
In your case, just access the array with the getter, take its item and call the setters: myObject.getOwners()[0].setUserId("001"); and myObject.getOwners()[0].setUserName("Freddy");, or assign the Owner to a local variable:
MyClass.Owner owner = myObject.getOwners()[0];
owner.setUserId("001");
owner.setUserName("Freddy");
Use getOwners which will return owners object then set the value.
myObject.getOwners()[0].setUserId("001");
myObject.getOwners()[0].setUserName("Freddy");

Spark SQL - Encoders for Tuple Containing a List or Array as an Element

Using Spark 2.2 + Java 1.8
I have two custom data types "Foo" and "Bar". Each one implements serializable.'Foo' has a one to many relationship with 'Bar' so their relationship is represented as a Tuple:
Tuple2<Foo, List<Bar>>
Typically, when I have a 1:1 relationship, I can encode to my custom types like so:
Encoder<Tuple2<Foo,Bar>> fooBarEncoder = Encoders.tuple(Encoders.bean(Foo.class),Encoders.bean(Bar.class));
and then use to encode my Dataset
Dataset<Tuple2<Foo,Bar>> fooBarSet = getSomeData().as(fooBarEncoder);
But I am having trouble finding a way to encode for the scenario when I have a list (or an array) as a Tuple2 element. What I would like to be able to do is to provide an encoder for the second element like this:
Encoder<Tuple2<Foo,List<Bar>>> fooBarEncoder = Encoders.tuple(Encoders.bean(Foo.class), List<Bar>.class);
and then encode to my dataset:
Dataset<Tuple2<Foo,List<Bar>>> fooBarSet = getSomeData().as(fooBarEncoder)
But obviously I cannot invoke .class on a parameterized type like List
I know that for String and primitive types, arrays are supported by spark implicits e.g.:
sparkSession.implicits().newStringArrayEncoder()
But how would I create an encoder for a List or Array of a custom class type?
I'm not sure how well this method could be implemented within your setup but here goes. Create a wrapper class for your list and try it out.
public class BarList implements Serializable {
List<Bar> list;
public List<Bar> getList() {
return list;
}
public void setList(List<Bar> l) {
list = l;
}
}
I'm don't know if it's possible. I tried the following Scala, trying to help, figuring that I could build up the encoder by first teaching spark how to encode X, then List[X] and finally a tuple containing List[X] (not shown below):
import org.apache.spark.sql.Encoders
import org.apache.spark.sql.catalyst.encoders.ExpressionEncoder
import scala.beans.BeanProperty
class X(#BeanProperty var field: String) extends Serializable
case class Z(field: String)
implicit val XEncoder1 = Encoders.bean(classOf[X])
implicit val ZEncoder = Encoders.product[Z]
val listXEncoder = ExpressionEncoder[List[X]] // doesn't work
val listZEncoder = ExpressionEncoder[List[Z]]
listZEncoder works fine
Switching to use
implicit val XEncoder2 = org.apache.spark.sql.Encoders.kryo[X]
Still doesn't work for listXEncoder
The error ends up at a place in catalyst ScalaReflection, which is beyond me.

Kotlin data class implementing Java interface

I'm trying to introduce Kotlin into my current project. I've decided to begin with entities, which seem to map perfectly to data classes.
For example I have a data class:
data class Video(val id: Long, val ownerId: Long, val title: String, val description: String? = null,
val imgLink: String? = null, val created: Date? = null, val accessKey: String? = null,
val views: Long? = null, val comments: Long? = null, val videoLink: String? = null): Entity
Which implements Java interface:
public interface Entity {
Long getId();
}
But for some reason compiler doesn't understand that method is implemented already:
Class 'Video' must be declared abstract or implement abstract member public abstract fun getId(): kotlin.Long! defined in net.alfad.data.Entity
Do I have to use any additional keywords for id param? What does "!" mean in the signature?
The problem here is that Kotlin loads the Java class Entity first and it sees getId as a function, not as a getter of some property. A property getter in a Kotlin class cannot override a function, so the property id is not bound as an implementation of the getId function.
To workaround this, you should override the original function getId in your Kotlin class. Doing so will result in JVM signature clash between your new function and id's getter in the bytecode, so you should also prevent the compiler from generating the getter by making the property private:
data class Video(
private val id: Long,
...
): Entity {
override fun getId() = id
...
}
Note that this answer has been adapted from here: https://stackoverflow.com/a/32971284/288456
If this is your whole data class then you're not overriding getId(). I see that you have a property called id and Kotlin should generate a getter for that but that won't be marked with the override keyword which you need to indicate that you're overriding an abstract function.
-- EDIT --
Alexander beat me to it! His answer is better anyway! ;)

How to mass annotate constructor arguments?

I've got a problem where I want to make a lot of classes in our project de-serializable via jackson. The problem is that most of classes look like this:
public class FinalFieds{
private final String field;
private final String secondField;
public FinalFieds(String field, String secondField)
{
this.field = field;
this.secondField = secondField;
}
public String getField()
{
return field;
}
public String getSecondField()
{
return secondField;
}
}
So what I found is that in jackson you can do something like this:
public FinalFieds(#JsonProperty("field") String field, #JsonProperty("secondField") String secondField)
And that works nice. The problem is that I cannot make structural replace in intellij to work for me. When I try:
All my matches are in "Unclassified matches" section.
Furthermore when I try to replace, Intellij just removes a constructor from the class.
Any idea on what I'm doing wrong or is it a known bug in intellij?
Even an overcomplicated regex that will help me replace this (for single argument constructors I can create it myself; the problem is that our constructors in those classes have multi-argument constructors).
It's a bug or a missing feature depending on how you look at it.
https://youtrack.jetbrains.com/issue/IDEA-141143
However, it is possible to do it in two steps. First search for the constructor parameters you want to annotate:
class $Class$ implements OurCommonInterface {
$Class$($Type$ $parameter$);
}
where $parameter$ min: 1 max: unlimited, This variable is target of the search checked.
Then replace the parameter with an annotated parameter in scope Previous Search Results:
$Type$ $parameter$
Replacement template:
#JsonProperty("$parameter$") $Type$ $parameter$

Enum with functions?

I saw the page:
I'm familiar with this SO question for creating enums in Python. However, I can't find an example anywhere of an enum that has functions.
I'm mainly a Java programmer.
I wrote this code in Java:
public enum Role {
SOLDIER(4),
DEMOMAN(2),
SCOUT(4),
MEDIC(2);
private final int maxPlayers;
private Role(int maxPlayers) {
this.maxPlayers = maxPlayers;
}
public int getMaxPlayers() { return maxPlayers; }
}
I tried to do the same in Python:
class Klass:
SCOUT = 1
SOLDIER = 2
DEMOMAN = 3
MEDIC = 4
#staticmethod
def maxPlayers(klass):
return {
Klass.SCOUT : 4,
Klass.SOLDIER : 4,
Klass.DEMOMAN : 2,
Klass.MEDIC : 2,
}[klass]
For some reason. I feel like I'm doing it wrong.
What is the best practice for associating functions to enums in Python?
I don't actually care if the suggested answer doesn't use an enum; I'm just trying to understand the best practice for implementing the above Java code in Python.
I'm willing to use this enum in the following:
class Players(dict):
def countKlass(self, klass):
count = len(filter(lambda x: x == klass, self.values()))
return count
Let's remember what enums in Java really are -- static final instances of a class. All they really are is just named constants.
Generally, python favors a looser (or if you prefer, more flexible) coding style than Java. Part of that is that there's no such thing as a constant, and part of it is trusting users of your code not to do crazy things. In that vein, you can get a similar effect to your java code by doing this:
class Role(object):
class RoleType(object):
def __init__(self, maxPlayers):
self.maxPlayers = maxPlayers
SOLDIER = RoleType(4)
DEMOMAN = RoleType(2)
SCOUT = RoleType(4)
MEDIC = RoleType(2)
Then you can access them like this
s = Role.SOLDIER
print s.maxPlayers # Prints 4
What this doesn't do is prevent users of your library from creating new roles. Doing so is slightly awkward, though, which should be a hint to the user that "they're doing it wrong".
newRole = Role.RoleType(22) # as an example
If you go this route, you just more or less have to live with that. If you favor using convention though, this generally won't be a problem. They can always just access the values you've defined.
If you are looking for best practices, typically you'd just make a dictionary.
klass = {'SCOUT':4,
'SOLDIER':4,
'DEMOMAN':2,
'MEDIC':2,}
print klass['MEDIC']
2
If you want this to be a class method you could say:
class Klass:
def maxPlayers(self, klass):
return {'SCOUT':4,
'SOLDIER':4,
'DEMOMAN':2,
'MEDIC':2,}[klass]
This is how you'd use it:
print Klass().maxPlayers('MEDIC')
2
Using the AutoEnum recipe, your code could look like this:
class Role(AutoEnum):
SCOUT = 4
SOLDIER = 4
DEMOMAN = 2
MEDIC = 2
def __init__(self, max_players):
self.max_players = max_players
And now you have the benefits of the new Python Enum (backported if you don't have 3.4):
--> Role.SCOUT
<Role.SCOUT: 3>
--> Role.SCOUT.max_players
4

Categories

Resources