class SomeClass in package x cannot be accessed in com.a.y.x - scala

I'm attempting to un-Spring IoC several Java classes and load them directly in some Scala code. Naturally I'm finding that there are name space conflicts between a package like
com.a.x.SomeClass
and
com.a.y.x.SomeClass
I've tried using the import name space resolvers like
import com.a.y.x.{ SomeClass => YYYSomeClass }
import com.a.x{ SomeClass => XXXSomeClass }
That cleans up the imports, but referring to those classes later in the classes show the error as hovers in the Typesafe ScalaIDE, and after clean compilations.
When I compile from the gradle scala plugin, or via the Typesafe ScalaIDE with scala 2.10.2 or 2.10.3, I get the following type of un-useful error messages:
class SomeClass in package x cannot be accessed in com.a.y.x
The problem occurs if I try to use a class from com.a.y.x that doesn't have a name space conflict. If I try some of the scalac flags, I've also been able to get a Warning out that's slightly different ( during the typer stage ):
class SomeClass in package x cannot be accessed in y.this.x
I'd really like to know if there's a way to expand the first package reference. I'm having trouble setting up an Eclipse project to debug the scalac compiler and I haven't found a scalac flag that adds useful information to the error.
The error occurs when I either try to ctx.getBean("someClass").asInstanceOf[XXXSomeClass] or new XXXSomeClass.
The this reference from the warning makes me think there's some object confusion going on. I don't think it's classpath issue in the larger project I'm working on because removing one jar removes the ability to resolve imports, however I can't reproduce it with simple example classes in a separate project.
A little more information on the java classes - the different, conflicting java packages are in separate jars that were compiled by a 1.6 flavor of Java. They are top level, public classes although two are singletons with private constructors and corresponding public static getInstance() methods.

It really is an access error. I think this is just a poor error message. The java was compiled separately and accessed from jar files. I hadn't paid enough attention to the package private nature of the classes I wanted to instantiate( I had seen "public" in front of some of them and not carefully checked all of them ). The name space collisions were a red-herring in this case and actually don't affect the output of the error message.
In some cases, there are public interfaces I can use instead with a little bit of Spring-glue to instantiate the objects and load them into the Scala class.
The scalac error message would have been more helpful if it had the form:
class SomeClass in package com.a.y.x cannot be accessed in totally.unrelated
where the first package reference is the Java class's package and the trailing package is the package of the Scala class trying to instantiate the Java class.
To recap - the Java class was like:
package com.a.y.x.SomeClass
class SomeClass extends SomeOtherClass implements SomeInterface
and needs to be like:
package com.a.y.x.SomeClass
public class SomeClass extends SomeOtherClass implements SomeInterface
to not get these access errors.
Since I have more control of the Scala here, on a whim I tried changing the package of a Scala class from totally.unrelated to com.a.x.y which then compiles cleanly. As you might guess, that merely defers the error to a run time error -> java.lang.IllegalAccessError. However, the IllegalAccessError from the Java has the description/package order that I think should happen in the compilation error from scalac:
...java.lang.IllegalAccessError: tried to access class com.a.y.x.SomeClass from class s.Trouble$delayedInit$body

Related

AbstractMethodError on obscure method name when upgrading from Scala 2.12 to 2.13

I am getting the following error:
java.lang.AbstractMethodError: Receiver class com.pack.ReceiverDAO does not define or inherit an implementation of the resolved method 'abstract void com$pack$proj$dao$JSDAO$_setter_$jsDAOApi_$eq(slick.jdbc.JdbcProfile$API)' of interface com.pack.proj.dao.JSDAO.
when I try to promote my code to Scala 2.13 from 2.12 (the dependency that's giving me issues, com.pack.proj, is compiled by Scala 2.12). I thought an easy way to get rid of this error is to implement a stub for it. However, at the moment, I don't have the source code for com.pack.proj.dao.JSDAO (which is what I extends in my "receiver", com.pack.ReceiverDAO) so I am not sure how to override com$pack$proj$dao$JSDAO$_setter_$jsDAOApi_$eq(slick.jdbc.JdbcProfile$API) w/o compilation errors like "overrides nothing". How can I override this inherited abstract method or otherwise get rid of this runtime error?
For the sake of completeness, I'd like to add that I needed to exclude some of the Scala_2.12-compiled Slick libraries when I declared the troublesome library, com.pack.proj as a dependency:
("com.pack.proj" % "js-dao_2.12" % ProjVer)
.exclude("com.typesafe.slick", "slick-hikaricp_2.12")
.exclude("com.github.tminglei", "slick-pg_2.12")
.exclude("com.typesafe.slick", "slick_2.12")
You simply cannot use a library that is compiled with 2.12 in a 2.13 project. It will inevitably break.
There is no real remedy other than use a version of that library that is compiled with 2.13, or not use it at all.
Make sure you're initialising your database in the same format as recommended. I.e. use a trait to define which extensions you wish to use and then extend this trait on a companion object.
import com.github.tminglei.slickpg._
trait MyPostgresProfile extends ExPostgresProfile
with PgArraySupport {
override val api = MyAPI
object MyAPI extends API with ArrayImplicits {
}
object MyPostgresProfile extends MyPostgresProfile
You can see a more complete example in the slick-pg README

Why does class name of a type in a package object contain "package" in runtime class name?

I'm trying to generate the runtime class name of a class that is defined in a package object.
Example:
package com.foo
package object bar {
case class MyCaseClass()
}
import bar._
MyCaseClass().getClass.getCanonicalName
The above will generate com.foo.bar.package.MyCaseClass
If I use WeakTypeTag it will correctly generate the type as com.foo.bar.MyCaseClass.
package com.foo
trait MyTrait
case class MyImpl extends MyTrait
def getType[T](t: T)(implicit weakTypeTag WeakTypeTag[T]): String = {
weakTypeTag.tpe.fullName
}
What is the reason for the above difference in behavior? I know I must be missing something about the Scala type system...
This isn't so much about the type system as about the encoding of package objects on the JVM. The JVM doesn't have package-level methods, for example, so the Scala compiler has to create a synthetic class that has static methods, inner classes, etc. corresponding to the definitions in the package object. That class is named package, an arbitrary but self-explanatory name that has the advantage of being a keyword in both Scala and Java, so it's unlikely to result in collisions with non-synthetic code.
Java's reflection APIs know nothing about Scala, so naturally they can't hide this encoding from you. When you call getClass.getCanonicalName you're seeing the actual class name, corresponding to the class file you'd find at com/foo/bar/package\$MyCaseClass.class when you compile your code.
Scala's reflection APIs do know about Scala's encoding of package objects, and they will hide the synthetic package class from you. This arguably makes sense, since the details of the encoding aren't in the spec (if I remember correctly?) and so may vary across platforms or language versions, etc.
The discrepancy is a little confusing, but this isn't the only time you'll run into differences—the Scala reflection API hides lots of mangling, etc. that Java reflection can't.

Scala 'this' and 'self' not working in simple App

New to scala (using version 2.12.1) obviously from the title. I'm writing my first app in IntelliJ. I've read about the Scala equivalent in Java to this. I've tried this, self, classOf[] and IntelliJ is complaining and the code is not compiling even if I ignore IntelliJ. Here's what I have:
import ch.qos.logback.classic.Logger
object Main extends App {
val logger = Logger[Main]
}
Logger package is importing correctly in SBT. However it cannot resolve the symbol Main. I tried sticking it in a package to make it less ubiquitous and then doing something like Logger[me.justin.Main] but that also doesn't work.
I also thought maybe extending App was causing some problems but I think that's fixed in the scala version I'm using? Maybe it's not even applicable?
I'm all Googled out. Help please!
You're getting tripped up by how Scala's objects work. Let's say we had a class Foo and a companion object for same:
class Foo
object Foo
If we wanted a logger for the class, we'd do the obvious thing:
val logger = Logger[Foo] // `Foo` here is the type of the class.
But what if we wanted to refer to the type of the object? We have to disambiguate from the type of the class. The answer is to use the special type member on the object:
val logger = Logger[Foo.type] // `Foo.type` here is the type of the object.
So in your case:
val logger = Logger[Main.type]

I can haz no package-private class in Scala?

Sorry for the catchy title. ;-)
I want to create a package-private class with a package-private method in Scala, so my class looks somewhat like this:
package net.java.truevfs.ext.pace
import ...
private[pace] abstract class AspectController(controller: FsController)
extends FsDecoratingController(controller) {
private[pace] def apply[V](operation: => V): V
... // lots of other stuff
}
However, if I use javap to check what the Scala compiler effectively creates, I get something like this:
$ javap -classpath target/classes net.java.truevfs.ext.pace.AspectController
Compiled from "AspectController.scala"
public abstract class net.java.truevfs.ext.pace.AspectController extends net.java.truevfs.kernel.spec.FsDecoratingController implements scala.ScalaObject{
public abstract java.lang.Object apply(scala.Function0);
...
}
This means that although the Scala compiler might respect the access restrictions, I could still call this class from any Java code, which is a clear encapsulation violation.
Am I missing something?
Is there a way to make this work as intended?
In addition to #Régis' answer, the reason Scala compiler doesn't make the class package-private is because by Scala rules it can be accessed from other packages: namely, subpackages of net.java.truevfs.ext.pace. E.g.
package net.java.truevfs.ext.pace.subpackage
import net.java.truevfs.ext.pace.AspectController
class Subclass extends AspectController { ... }
is legal in Scala, but in Java classes from net.java.truevfs.ext.pace.subpackage can't access package-private classes from net.java.truevfs.ext.pace.
You are not missing anything.
Many of the access restricitons in scala have no equivalent in java nor at the jvm level. The additional information is obviously right there in the .class file, but is there as custom annotations that only the scala compiler will interpret.
The scala object model can only partly be matched to the jvm object model, and a java compiler will only see this partial model.
I'd say that the match is pretty close and the scala compiler does a very good job at java interoperability, but nothings's perfect.
Not really a 100% correct answer...
You can make a package object if I want to do some fancy stuff in there with a private class. The package object is accessed like any other package.
The class MyClass is package private to that package object.
It's not package private however.
package object com.jasongoodwin.foo {
private class MyClass
class AnotherClass {
val myClass = new MyClass
}
}

How do I force the Scala compiler to tell me when my class is abstract?

Why is the "abstract" keyword for class definition optional in Scala, and how do I force the Scala compiler to tell me when my class is abstract?
Here an example that I wrote in Eclipse:
class Toto[T] {
def get(index: Int): T
}
object Toto {
def create[T]: Toto[T] = new Toto[T]
}
This seems to be a perfectly valid class definition in Scala, although it does NOT define the required get method, and is NOT prefixed with abstract. If you don't need the abstract keyword, then why does it exist? And if you want to be told that your class is actually abstract, how do you get the compiler to tell you?
This is not valid scala code, abstract is required, and instanciation forbidden. From the spec (5.2, p63):
The abstract modifier is used in class
definitions. It is redundant for
traits, and mandatory for all other
classes which have incomplete members.
Ab- stract classes cannot be
instantiated (§6.10) with a
constructor invocation unless
followed by mixins and/or a refinement
which override all incomplete members
of the class. Only abstract classes
and traits can have abstract term
members.
The code produces an error in the REPL : error: class Toto needs to be abstract, since method get is not defined
I get the proper behavior with the same message in Eclipse too. You should check whether you get the same error with and without eclipse. Whichever is true, I guess if you have exactly the code you posted without an error (does it run?), a bug repport will be warranted.
To answer my own question: In Eclipse, you can only tell if a class is correct if all other classes compile without errors! In other word, you can't trust anything Eclipse says about a class unless there are no errors in other classes.
So if you have errors in several classes, then there is no way of knowing which ones are the real errors, and neither if a class without errors is correct.
You just have to repeatedly loop on the errors, fixing any one that makes sense, and hoping the others errors that don't make sense are eventually going to just disappear.