So there's a lot of questions and examples around of reading external .class files using a ClassLoader but I'm struggling to see where I'm going wrong.
val folderUrl: URL = new File("D:/tmp/").toURI.toURL //file:/D:/tmp/
val cl: URLClassLoader = new URLClassLoader(Array(folderUrl), this.getClass.getClassLoader)
cl.loadClass("my.package.MyClassName")
The last line throws a ClassNotFoundException
The folder D:/tmp/ contains a class file "MyClassName.class".
The class has the package "my.package"
The class is called "MyClassName"
I can't understand what I'm doing wrong?
EDIT:
The two closest question which relate are:
Scala - Dynamic object/class loading
How do I call a Scala Object method using reflection?
But these both do not have my problem however, they both get further than I have done where they successfully load the class before running into issues.
So the issue was the fact that the folder structure did not match the package name.
So my folder structure was
D:/tmp/MyClassName.class
The full class name was
my.package.MyClassName
The class loader requires that the folder structure be
D:/tmp/my/package/MyClassName.class
Related
I am trying to read a file as input stream and then convert the contents of the file into a list in scala. Here is my code
val fileStream = getClass.getResourceAsStream("src/main/scala-2.11/com/dc/returnsModel/constants/abc.txt")
val item_urls = Source.fromInputStream(fileStream).getLines.toList
This does now work. I get a NullPointer Exception.
How do I correct this?
However, this works(but I cant use it in a JAR File)
val item_urls = Source.fromFile("src/main/scala-2.11/com/dc/returnsModel/constants/aa.txt").getLines.toList
getClass.getResourceAsStream does not expect a full path, it searches for the requested file in the classpath using the same class loader as the current class.
Fixing this depends a bit on the structure of your project and class that calls this code:
If the class returned by getClass is in the same package as the file you're trying to load (com.dc.returnsModel.constants), then you should simply reference the file name only:
getClass.getResourceAsStream("abc.txt")
If the class returned by getClass resides in a different package, path should start with a / which represents the root of the classpath, hence the package name must follow:
getClass.getResourceAsStream("/com/dc/returnsModel/constants/abc.txt")
You have to provide the correct path starting from root.
Here root is start of your src/scala-2.11 folder in your case.
One example
object SO extends App {
val resourceStream = SO.getClass.getResourceAsStream("/com/sm.txt")
println(Source.fromInputStream(resourceStream).getLines.toList)
}
I have a maxforlive device using java/mxj.
I used all of these options to include my java files during development:
Including my (maven) target/classes directory through max.java.config.txt.
Adding a directory through Options > File Preferences
Adding a jar to the automatically generated (OSX) ~/Documents/Max 7/Max for Live Devices/MyProject Project/ directory
All of these paths work fine i.e. the files are picked up and my mxj object works.
However, when i freeze the device for publication, java files are not included from any of those paths.
I tried to make sense of
https://docs.cycling74.com/max7/tutorials/jitterchapter99_appendixd although I'm not building a standalone, but a freezed maxforlive device, so I included max.jar and mxj.mxo in the Project folder which did not work either.
When I copy my target/classes or target/classes/myproject folder into the generated Project folder (/code, /code/classes, /classes), max moves all the class files out into /code, creating a lot of work for me while not even picking the classes up for dev.
I saw devices on maxforlive.com with properly included java files, so I know it can be done. How can I achieve this?
Unfortunately this is a long standing bug in MFL.
Here is a movie from 2012 where I reproduce this, it has not been fixed since. http://arttech.nl/projectjavaissue.mov
This means that the only way to distribute MFL devices with java class files is to include them separately.
Ok, so here it is: Including just a single class with no other class dependencies except MaxObject works fine. There's also no need to add .java files like I said in my previous comment.
All you need to do is:
have the working mxj object in your patcher (doesn't matter where you saved it)
click the button on the bottom that says "Show containing project" on hover
add your classfile
freeze
When you have more classes, it gets complicated.
1) If you have your typical java hierarchy with folders and subfolders, that won't work. As you have to add each file separately, the hierarchy will be destroyed. Use a jar and add it to the containing project.
2) Here it comes, believe it or not: All the classes you are going to use will have to be loaded on first instantiation. I call it static class allocation ;)
A way to achieve that:
create a new instance of every class in the constructor of the class that extends MaxObject or any other constructors it calls. That includes classes with only static methods.
if you happen to use interfaces and create implementations of those dynamically (new Runnable() {...}), don't. Dynamic implementations are new classes.
Fun fact: you can override methods of classes, too. So go
class Runner {
public void run() { throw new Exception("not implemented"); }
}
then you can dynamically create a
new Runner() {
public void run() {
MaxObject.post("Even Mr. Gosling says interfaces were a mistake!");
}
}
Don't believe it? I don't blame ya. Look at
https://github.com/mihop/mxj-wsserver
and
http://www.maxforlive.com/library/device/3809
to be converted.
I am trying to write a Scala Play web service that returns JSON objects and am having trouble calling a function in a dependency. Can someone tell me what I'm doing wrong in this simplified example?
I have a project called SimpleJSONAPI that consists of the following object.
package com.github.wpm.SimpleJSONAPI
import play.api.libs.json.{JsValue, Json}
object SimpleJSONAPI {
def toJson(s: String): JsValue = Json.toJson(Map("value" -> s))
}
Unit tests confirm that given a string it returns a JSON object of the form {"value":"string"}.
I have a separate Play 2.2.3 Scala project that I created by typing play new PlayJSON. I added the following json action to the controller in the generated application.
package controllers
import play.api.mvc._
import com.github.wpm.SimpleJSONAPI._
object Application extends Controller {
def index = Action {
Ok(views.html.index("Your new application is ready."))
}
def json = {
val j = SimpleJSONAPI.toJson("The JSON API")
Action {
Ok(j)
}
}
}
I also added this route.
GET /json controllers.Application.json
In the root of the PlayJSON project I have a lib directory that contains the simplejsonapi_2.11.jar built by SimpleJSONAPI. This appears to contain the correct code.
> jar tf lib/simplejsonapi_2.11.jar
META-INF/MANIFEST.MF
com/
com/github/
com/github/wpm/
com/github/wpm/SimpleJSONAPI/
com/github/wpm/SimpleJSONAPI/SimpleJSONAPI$.class
com/github/wpm/SimpleJSONAPI/SimpleJSONAPI.class
This compiles, but when I try to connect to localhost:9000/json I get the following runtime error in the line with the val j assignment.
java.lang.NoSuchMethodError: scala.Predef$.ArrowAssoc(L/java/lang/Object;)Ljava/lang/Object;
I've also seen the same error in a unit test that exercises the /json route with a FakeRequest.
If I copy the toJson function from the external dependency into the Play application everything works.
As far as I can tell from the documentation I'm doing everything right, and the error message is opaque. Can someone tell me how to get this to work?
I think your import is incorrect given how you are using the API. Either exclude the object name on the import...
import com.github.wpm.SimpleJSONAPI._
Or change your usage to drop the object name...
val j = toJson("The JSON API")
This was a problem with Scala compiler version compatibility. I compiled my SimpleJSONAPI dependency with Scala 2.11, while the Play app was being built with Scala 2.10. When I changed the SimpleJSONAPI dependency to also build with Scala 2.10, I was able to use it in my Play app.
This was confusing because it's not obvious from the project files which version of Scala a Play app is using, and the error message about ArrowAssoc gives no indication that it is a compiler version issue.
I am trying to serialize a object in GWT using SerializationFactory, but I am not able to get it working. Here is the sample code of my POC:
import com.google.gwt.user.client.rpc.SerializationException;
import com.google.gwt.user.client.rpc.SerializationStreamFactory;
import com.google.gwt.user.client.rpc.SerializationStreamReader;
import com.google.gwt.user.client.rpc.SerializationStreamWriter;
...........
Some code here....
.........
......
SerializationStreamFactory factory = (SerializationStreamFactory) GWT.create(MyClass.class);
SerializationStreamWriter writer = factory.createStreamWriter();
try {
writer.writeObject(new MyClass("anirudh"));
String value = writer.toString();
SerializationStreamReader reader = factory.createStreamReader(value);
MyClass myObj = (MyClass) reader.readObject();
System.out.println(myObj.getName());
} catch (SerializationException e) {
e.printStackTrace();
}
It gave me the following exception
Caused by: java.lang.RuntimeException: Deferred binding failed for 'com.anirudh..client.MyClass' (did you forget to inherit a required module?)
also in my code the class whose object I am trying to serialize implements IsSerializable
MyClass implements IsSerializable
I don't want to use GWT Auto-Bean framework because it does not fit my use case. Also I am not using GWT-RPC framework and right now I am quite adamant about using SerializationStreamFactory :D because I seriously want to know how this thing works.
Can anyone share a working example of SerializationStreamFactory or help me out pointing any mistake(s) I did.
Thanks in advance
SerializationStreamFactory factory = (SerializationStreamFactory) GWT.create(MyClass.class);
What are you expecting this line to do? GWT will attempt to find a replace-with or generate-with rule that matches this class (either when-type-assignable or when-type-is), or failing that will attempt to invoke a zero-arg constructor on MyClass, effectively new MyClass(). Is this what you are expecting?
The selected exception you've pasted suggests that MyClass may not be on the source path that GWT has been given to compile from, but the full error log will provide more information.
It looks as though you are trying to mimic the generated RPC code, where a *Async rpc interface would be implemented by code that extends from com.google.gwt.user.client.rpc.impl.RemoteServiceProxy (which implements SerializationStreamFactory). That base implementation is extended further to initialize several fields such as the com.google.gwt.user.client.rpc.impl.Serializer instance, actually responsible for serializing and deserializing object streams.
Serializers are created (by default) from the base class of com.google.gwt.user.client.rpc.impl.SerializerBase, through the rebind class com.google.gwt.user.rebind.rpc.TypeSerializerCreator. If you've build your own generator for MyClass, you should be kicking this off to get the work done as ProxyCreator already should be doing.
Remember when building your own serialization/deserialization mechanism that you need to decide which types can be marshalled within this system - if you open it to all types, then you will need to generate FieldSerializer types for all possible objects on the source path. This will greatly expand the size of your compiled code.
If your main goal is learning how this 'magic' works, dig into the generators and associated code that live in the com.google.gwt.user.rebind.rpc package. There are other libraries that leverage these ideas such as the gwt-atmosphere project (see https://github.com/Atmosphere/atmosphere to get started). Also review the generated code that GWT creates when it builds a 'tradition' RPC interface.
I am writing a Scala class to inherit from a Java class, and I must override a method that takes a protected Java inner class as a parameter. The Java dependency comes as a jar without source code.
I have the exact same setup as found in https://issues.scala-lang.org/browse/SI-3120 except that I do not have the Java source code available, so scalac only knows about the Java dependency by looking at the byte code (in jar or class files).
This is basically what I'm trying to do:
// javapkg/JavaSuperClass.java
package javapkg;
public class JavaSuperClass {
protected class JavaInnerClass {
}
public void method(JavaInnerClass javaInnerclass) {
System.out.println("hello");
}
}
// scalapkg/ScalaSubClass.scala
package scalapkg
import javapkg.JavaSuperClass
class ScalaSubClass extends JavaSuperClass {
override def method(javaInnerClass: JavaSuperClass#JavaInnerClass) {
println("world")
}
}
I have Java Sun JDK Hotspot 1.6.0_24 and Scala 2.9.0.1 on Linux. This is what happens:
$ cd javapkg
$ javac JavaSuperClass.java
$ cd ../scalapkg
$ scalac -cp .. ScalaSubClass.scala
ScalaSubClass.scala:6: error: class JavaInnerClass in class JavaSuperClass cannot be accessed in javapkg.JavaSuperClass
Access to protected class JavaInnerClass not permitted because
prefix type javapkg.JavaSuperClass does not conform to
class ScalaSubClass in package scalapkg where the access take place
override def method(javaInnerclass: JavaSuperClass#JavaInnerClass) {
^
one error found
Note, if I change JavaSuperClass#JavaInnerClass to simply JavaInnerClass, I get this:
ScalaSubClass.scala:6: error: method method overrides nothing
override def method(javaInnerClass: JavaInnerClass) {
^
one error found
Note: I know this sounds very similar to the common "protected static inner class" Java-compatibility issue in Scala, but I believe this is unrelated because there are no statics anywhere in my example.
I feel like something is wrong, because when I put the same code into a mixed java/scala project in Eclipse, it seemed to compile fine (with the latter JavaInnerClass syntax); it's only when I compile the Scala code with only the Java byte code (and no Java source code) that I cannot get it to work. Am I just completely missing the correct syntax to refer to a Java inner class, is this a known defect, or should I file a compiler bug? I couldn't find anything about this exact use case in my searching.
This is an excellent article that discuss the topic.
EDIT-1
My bad, I answered to quickly. This actually may be a bug Mike, I'm trying to see if I can find a hack around. I'll let you know if I find one.
EDIT-2
I've tried different things but I can't find a way to make it work. Mike I'd suggest you to file a bug report.