Strange scala java interoperability behavior - java

I ran into the following Java compiler warning issue (using IntelliJ 14):
I have the following class in my Scala library:
object ScalatoJava {
def asJava[A,B](map: Map[A,B]): java.util.Map[A,B] = { map.asJava }
def asJava[A](list: List[A]): java.util.Collection[A] = {list.asJavaCollection}
}
I use it to convert few collections coming from Scala in my Java program.
Now in my Java program I have the following code for which IntelliJ is underlying in red stating that it can't resolve things:
private final java.util.Map<String, FieldSettings> poolpartyfieldsettings =
ScalatoJava.asJava(poolpartyConnectorSettings.fieldsSettingsMap());
It says it can not resolve the method asJava(scala.collection.immutable.Map<String, org.....FieldSettings>).
While if I write either
private final java.util.Map <String, FieldSettings> poolpartyfieldsettings =
ScalatoJava.asJava((scala.collection.immutable.Map<String, FieldSettings>)poolpartyConnectorSettings.fieldsSettingsMap());
or
scala.collection.immutable.Map<String, FieldSettings> poolpartyfieldsettings =
poolpartyConnectorSettings.fieldsSettingsMap();
ScalatoJava.asJava(poolpartyfieldsettings)
the compiler does not complain.
Here is the PoolpartyConnectorSettings Scala class:
trait DspacePoolPartyConnectorSettings {
def poolpartyServerSettings : PoolpartySettings
def fieldsSettingsList : List[FieldSettings]
def fieldsSettingsMap : Map[String, FieldSettings]
}
case class DspaceDspacePoolPartyConnectorSettingImpl (configUri: String) extends DspacePoolPartyConnectorSettings {
private val config = ConfigFactory.parseURL(new URL(configUri)).resolve()
private val configFieldSettinglist = config.getConfigList("PoolPartyConnectorSettings.FieldSettings").asScala.toList
private val configPoolPartySetting = config.getConfig("PoolPartyConnectorSettings.PoolPartySettings")
val poolpartyServerSettings = PoolpartySettings( configPoolPartySetting.getString("apirootEndpoint"),
configPoolPartySetting.getString("thesaurusapiEndpoint"),
configPoolPartySetting.getString("extratorapiEndpoint"),
configPoolPartySetting.getString("coreProjectId"),
configPoolPartySetting.getString("coreThesaurusUri"),
configPoolPartySetting.getString("jelProjectId"),
configPoolPartySetting.getString("jelThesaurusUri"))
val fieldsSettingsList = configFieldSettinglist map { e =>
FieldSettings(e.getString("fieldname"), e.getBoolean("treeBrowser"),
e.getBoolean("multilanguage"), e.getStringList("languages").asScala.toList,
e.getBoolean("closed"), e.getString("scheme"), e.getString("poolpartyProjectId"))
}
val fieldsSettingsMap = Map(fieldsSettingsList map {e => (e.fieldName, e)}: _*)
}
Any idea what the problem might be?

Related

scala to java conversion for user-defined function (UDF) in sparksql

spark.sqlContext.udf.register('dataSource', (data: scala.collection.mutable.WrappedArray$ofRef, ofType : String) => {
var flag = ''
try{
val array: Seq[String] = data.flatten(x => Seq(x.toString()))
array.foreach(s => if(s.contains(ofType)) { flag = ofType })
}
catch {
println("Exception :" + x.getMessage)
flag = ''
}
flag;
})
It is not required to convert this Scala code into Java code. In Spark you can register a UDF in any of the languages and also make use of it in either Java or Scala as long as it is used in the same SparkSession or Context.

Updates with a script ElasticSearch API not accepting Scala Map

I came across a use-case where I need to update a specific field in the ElasticSearch document. So for this use-case, I have used the Update API with a script ES doc. But I faced an issue(compilation error) with Script Constructor which accepts the following parameters:--> type, lang, idOrCode and params and the issue was with params(java.util.Map) parameter.
I have even tried the Scala to Java converters but could not solve it.
Code snippet
import org.elasticsearch.action.update.UpdateRequest
import org.elasticsearch.client.RequestOptions
import org.elasticsearch.script.{Script, ScriptType}
object Testing extends App {
val result = updateByScript("testing", "hW7BBnQBn2nWmIjS_b0C", 10.0)
println("######result:---> " + result)
high_level_client.close()
def updateByScript(index: String, id: String, count: Double) = {
//import scala.collection.JavaConversions.mapAsJavaMap
//import collection.JavaConverters._
import scala.collection.JavaConverters._
val updateRequest = new UpdateRequest(index, id)
val params = Map[String, Double]("count" -> count)
val script = new Script(ScriptType.INLINE, "painless", "ctx._source.count += params.count", mapAsJavaMap(params))
updateRequest.script(script)
high_level_client.update(updateRequest, RequestOptions.DEFAULT)
}
}
For the above issue, I have tried the Script Constructor with the idOrCode parameter and which solved my use-case but still I did not get the solution for other Script Constructors.
Working code with Constructor which accept idOrCode parameter.
Code snippet
import org.elasticsearch.action.update.UpdateRequest
import org.elasticsearch.client.RequestOptions
import org.elasticsearch.script.{Script, ScriptType}
object Testing extends App {
val result = updateByScript("testing", "hW7BBnQBn2nWmIjS_b0C", 10.0)
println("######result:---> " + result)
high_level_client.close()
def updateByScript(index: String, id: String, count: Double) = {
val updateRequest = new UpdateRequest(index, id)
val script = new Script(s"""ctx._source.count += $count""")
updateRequest.script(script)
high_level_client.update(updateRequest, RequestOptions.DEFAULT)
}
}

Sending PythonJavaClass into Java function with pyjnius

I'm trying to send a PythonJavaClass (NokeServiceListener) into mNokeService.registerNokeListener() but it keeps erroring out there and when printing the NokeServiceListener object I'm getting nokeLock.NokeServiceListener object at 0x97389b70 which doesn't look like a java object and then I get an error JNI DETECTED ERROR IN APPLICATION: use of invalid jobject 0x6e617278
from jnius import autoclass,PythonJavaClass,cast,java_method
Context = autoclass('android.content.Context')
Parcelable = autoclass('android.os.Parcelable')
Intent = autoclass('android.content.Intent')
Uri = autoclass('android.net.Uri')
PythonActivity = autoclass('org.kivy.android.PythonActivity')
NokeDeviceManagerService = autoclass('com.noke.nokemobilelibrary.NokeDeviceManagerService')
#LocalBinder = autoclass('com.noke.nokemobilelibrary.NokeDeviceManagerService$LocalBinder')
NokeDevice = autoclass('com.noke.nokemobilelibrary.NokeDevice')
NokeMobileError = autoclass('com.noke.nokemobilelibrary.NokeMobileError')
#NokeServiceListener =autoclass('com.noke.nokemobilelibrary.NokeServiceListener')
global mNokeService
##run_on_ui_thread
class NokeApi():
def __init__(self):
self.python_activity = PythonActivity.mActivity
self.service_connection = ServiceConnection()
def initiateNokeService(self):
currentActivity = cast('android.app.Activity', self.python_activity)
context = cast('android.content.Context', currentActivity.getApplicationContext())
nokeIntent = Intent()
nokeIntent.setClassName(context, 'com.noke.nokemobilelibrary.NokeDeviceManagerService')
self.python_activity.bindService(nokeIntent,self.service_connection,Context.BIND_AUTO_CREATE)
def onCreate(self):
self.initiateNokeService()
##run_on_ui_thread
class ServiceConnection(PythonJavaClass):
__javainterfaces__ = ['android.content.ServiceConnection']
__javacontext__ = 'app'
#java_method('(Landroid/content/ComponentName;Landroid/os/IBinder;)V')
def onServiceConnected(self,className, rawBinder):
print 'debug1'
#nokeDeviceManagerService = NokeDeviceManagerService()
#localBinder = LocalBinder()
nokeService = cast('com.noke.nokemobilelibrary.NokeDeviceManagerService$LocalBinder',rawBinder)
global mNokeService
mNokeService = nokeService.getService()
print mNokeService
#mNokeService = ((NokeDeviceManagerService.LocalBinder)rawBinder).getService()
print 'debug2'
mNokeServiceListener = NokeServiceListener()
#mNokeServiceListener = cast('com.noke.nokemobilelibrary.NokeServiceListener',nokeServiceListener)
print mNokeServiceListener
print 'debug2.5'
mNokeService.registerNokeListener(mNokeServiceListener)
print 'debug3'
noke1 = NokeDevice("NOKE3P", "F7:F3:F1:2C:66:25")
print 'debug4'
mNokeService.addNokeDevice(noke1)
print 'debug5'
mNokeService.setUploadUrl("https://coreapi-sandbox.appspot.com/upload/")
print 'debug6'
mNokeService.startScanningForNokeDevices()
print "Scanning for devices"
if not mNokeService.initialize():
print "Unable to initialize Bluetooth"
class NokeServiceListener(PythonJavaClass):
__javainterfaces__ = ['com.noke.nokemobilelibrary.NokeServiceListener']
__javacontext__ = 'app'
def __init__(self):
pass
#java_method('(Lcom/noke/nokemobilelibrary/NokeDevice;)V')
def onNokeDiscovered(self,noke):
print "Connecting to Noke"
mNokeService.connectToNoke(self,noke)
#java_method('(Lcom/noke/nokemobilelibrary/NokeDevice;)V')
def onNokeConnecting(self,noke):
print "Connecting"
#java_method('(Lcom/noke/nokemobilelibrary/NokeDevice;)V')
def onNokeConnected(self,noke):
print "Noke Connected"
self.requestUnlock(noke)
#java_method('(Lcom/noke/nokemobilelibrary/NokeDevice;)V')
def onNokeSyncing(self,noke):
print "NOKE SYNCING"
#java_method('(Lcom/noke/nokemobilelibrary/NokeDevice;)V')
def onNokeUnlocked(self,noke):
print 'Noke Unlocked'
#java_method('(Lcom/noke/nokemobilelibrary/NokeDevice;)V')
def onNokeDisconnected(self,noke):
print "Noke Disconnected"
self.mNokeService.uploadData()
self.mNokeService.startScanningForNokeDevices()
#java_method('(I)V')
def onBluetoothStatusChanged(self,bluetoothStatus):
pass
#java_method('(Lcom/noke/nokemobilelibrary/NokeDevice;ILjava/lang/String;)V')
def onError(self,noke, error, message):
pass
def requestUnlock(self,noke):
msg = '{"function":"Noke_Unlock","session":"%s","mac":"%s"}' % (noke.getSession(),noke.getMac())
rsp = connectToServer(_host, _port, msg)
if rsp['result'] == "success":
commandStr = rsp["commands"]
noke.sendCommands(commandStr)
else:
print "Access Denied"
I feel like there error is because I'm passing in a non java object into a java function but I've already tried to cast the object as a 'com.noke.nokemobilelibrary.NokeServiceListener' and that didn't work either. The code always errors out after debug 2.5 so something is going wrong between those two steps but I can't figure out what.
class NokeServiceListener(PythonJavaClass):
def __init__(self, callback):
super().__init__()
self.callback = callback
It will work because python is not java / C#. base class init will not called unless you explicitly write it.
Adding
class NokeServiceListener(PythonJavaClass):
def __init__(self, callback):
super(NokeServiceListener, self).__init__()
self.callback = callback
seemed to fix this issue... no idea why though.

Calling Java library method with (Object ...) arg list from Scala , retaining type sanity (Shapeless / Scalaz)

I am using the datastax java drver for Cassandra from scala (2.10.4)
to build batches of prepared statements
but have hit the following problem.
Table definition in CQL
use ks;
drop table bc_test;
create table bc_test(
id TEXT,
id_1 BIGINT,
c1 COUNTER,
c2 COUNTER,
PRIMARY KEY(id, id_1)
);
First problem is implicit numeric widening error
import com.datastax.driver.core.{ResultSet, ProtocolOptions, Cluster, Session}
import com.datastax.driver.core.RegularStatement
import com.datastax.driver.core.PreparedStatement
import com.datastax.driver.core.BoundStatement
import com.datastax.driver.core.BatchStatement
val c = Cluster.builder().addContactPoint("127.0.0.1").withPort(9042).build
val sess = c.connect("ks")
val p_bc_test_c1: PreparedStatement =
sess.prepare("UPDATE bc_test SET c1 = c1 + ? WHERE id = ? and id_1 = ?")
val batch: BatchStatement = new BatchStatement(BatchStatement.Type.COUNTER);
val id1: Long = 1L
val idText: String = "one"
val c1: Long = 1L
batch.add(p_bc_test_c1.bind(c1, "one", id1))
// which gives the error
scala> batch.add(p_bc_test_c1.bind(c1, "one", id1))
<console>:19: error: implicit numeric widening
batch.add(p_bc_test_c1.bind(c1, "one", id1))
^
I can get around this using type ascription but wanted to find something a bit nicer
that can also be built into a more generic solution. What I came up with was :
import scalaz._
import Scalaz._
import shapeless._
import poly._
import syntax.std.tuple._
trait CassandraLongVal
type CassandraLong = java.lang.Long ## CassandraLongVal
def cassandraLongCol(c : Long): CassandraLong = Tag(c)
trait CassandraIntVal
type CassandraInt = java.lang.Integer ## CassandraIntVal
def cassandraIntCol(c : Int): CassandraInt = Tag(c)
object ToCassandraType extends Poly1 {
implicit def caseInt = at[Int](cassandraIntCol(_))
implicit def caseLong = at[Long](cassandraLongCol(_))
implicit def caseString = at[String](identity)
}
case class Update1(cval: Long, id: String, id1: Long)
val update1Gen = Generic[Update1]
val bUpdate1 = Update1(125L, "two", 1L)
val update1AsArray = update1Gen.to(bUpdate1).map(ToCassandraType).toArray
batch.add(p_bc_test_c1.bind(update1AsArray:_*))
batch.add(p_bc_test_c1.bind(update1AsArray:_*))
sess.execute(batch)
This seems to work quite happily and I can use the basic pattern for dozens of table with different columns.
Is this a reasonable approach, or is there a simpler way to get the same outcome whilst trying to keep a handle on the types
and am I abusing scalaz/ shapeless through my (considerable) ignorance.

Perl, Inline_Java, Java dynamic load of object and method

Can anyone assist me on how do I load the object FooBar dynamically and call the roquet function (dynamically) ?
I have this snippet in Perl:
#!/usr/bin/perl -w
use Inline Java => << 'End_Of_Java_Code';
class FooBar {
public FooBar(){}
public void roquet() {
System.out.println("HELLO!");
}
}
End_Of_Java_Code
use Data::Dumper;
use Class::Sniff;
my $sniff = Class::Sniff->new({class=>'FooBar'});
my $num_methods = $sniff->methods;
my $num_classes = $sniff->classes;
my #methods = $sniff->methods;
my #classes = $sniff->classes;
my #unreachable = $sniff->unreachable;
foreach my $method (#methods) {
if ( $method eq "roquet" ) {
print "$method\n";
}
}
I tried the following approaches and variations:
a. approach:
use Module::Load
my $package = "main::FooBar";
load $package;
$package->new();
$package->$rflmethod;//where rflmethod is the variable: $rflmethod='roquet';
b. approach:
no strict 'refs';
use Package::Stash;
my $stash = Package::Stash->new('main::FooBar');
my $coderef = $stash->get_symbol('&__new');
$coderef->()
This works:
my ($class, $method) = qw(FooBar roquet);
my $f = $class->new;
$f->$method;

Categories

Resources