Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Null pointer exception from descriptorOf(Type) #2

Open
christophercurrie opened this issue Nov 14, 2011 · 8 comments
Open

Null pointer exception from descriptorOf(Type) #2

christophercurrie opened this issue Nov 14, 2011 · 8 comments

Comments

@christophercurrie
Copy link

This REPL transcript uses the source cloned from Github (at the time of writing).

scala> import org.scalastuff.scalabeans.Preamble._
import org.scalastuff.scalabeans.Preamble._

scala> import scala.collection._
import scala.collection._

scala> classOf[SortedMap[String,String]]
res0: java.lang.Class[scala.collection.SortedMap[String,String]] = interface scala.collection.SortedMap

scala> descriptorOf(res0)
java.lang.NullPointerException
    at org.scalastuff.scalabeans.BeanIntrospector$.classExtent$1(BeanIntrospector.scala:40)
    at org.scalastuff.scalabeans.BeanIntrospector$.classExtent$1(BeanIntrospector.scala:40)
    at org.scalastuff.scalabeans.BeanIntrospector$.apply(BeanIntrospector.scala:101)
    at org.scalastuff.scalabeans.Preamble$.descriptorOf(Preamble.scala:31)
    at .<init>(<console>:15)
    at .<clinit>(<console>)
    at .<init>(<console>:11)
    at .<clinit>(<console>)
    at $export(<console>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:592)
    at scala.tools.nsc.interpreter.IMain$Request$$anonfun$10.apply(IMain.scala:828)
    at scala.tools.nsc.interpreter.Line$$anonfun$1.apply$mcV$sp(Line.scala:43)
    at scala.tools.nsc.io.package$$anon$2.run(package.scala:31)
    at java.lang.Thread.run(Thread.java:680)
@advorkovyy
Copy link
Collaborator

ScalaBeans is not generic reflection framework, it is intended to work with beans only. Naked interfaces are not supported because you do not have a constructor and cannot create new instances. Collection is doubtful example of a bean anyway. What you can do is define a bean with a property of one of collection classes. There interfaces are supported as long as there is a builder in the companion object.

Sorted collections are not supported because we cannot determine at runtime which Ordering[Key] implementation must be used. It is injected via implicits in the code that instantiates new collection. We cannot access it with reflection.

Further, if you define your bean in REPL, it will be compiled as inner class AFAIK. Inner classes look different from reflection point of view. Often they get extra constructor parameters and other peculiarities making reflection part easily screwed up without any logical solution in generic case. We do not support inner classes, only top-level.

So, basically, you just get (un)lucky to think of an example which get most problems hit for any bean reflection framework :)

I will add more descriptive error message in case anyone tries to feed an interface to BeanIntrospector.

@advorkovyy
Copy link
Collaborator

What you can do is get ScalaType of your type:

scalaTypeOf[SortedMap[String, String]]

ScalaType is useful because:

  1. You can pattern-match it
  2. Type arguments are also of ScalaType and you can match them as well
  3. There is extra functionality added to some types. For collection types you can get a builder specific for that very type you have on hand (like List, Seq, Vector, Set, Map etc). It works for all types except sorted collections for reasons I've mentioned before.

@christophercurrie
Copy link
Author

scalaTypeOf looks exactly like what I want for my use case thanks. The only missing piece is that it doesn't look like its currently able to figure out if the generic parameter types are subclasses of AnyVal, such that

scala> scalaTypeOf(classOf[List[Int]])
res0: org.scalastuff.scalabeans.types.ScalaType = List[Object]

It's my understanding that this information is in the ScalaSig somewhere, it's just some work to find it. Do you have plans to add this support, or am I misinformed about what the ScalaSig contains?

@advorkovyy
Copy link
Collaborator

ScalaSig parser is there. ScalaSig is a Java annotation on the class level containing compiler symbol tables. It is added by Scala compiler to all top-level classes. classOf[...] doesn't contain neither ScalaSig nor generic type arguments. That's why it is List[Object], there is nothing more from reflection point of view. If you define a property with type List[Int] it is completely different story. There is GenericType from Java reflection and ScalaSig. Both are used to get ListType(IntType).

@advorkovyy
Copy link
Collaborator

top-level class = class defined within package

Inner classes are described in ScalaSig of top-level classes/objects. As I told, their instantiation and view from Java reflection is not trivial: all implicit dependencies from containing classes/objects are added there explicitly and in generic case are difficult to translate to meaningful API. This is the reason we do not support classes defined in REPL - it uses inner classes under the hood.

@christophercurrie
Copy link
Author

Ah, I get it. There has to be a containing object to hold the List in order for there to be a ScalaSig that describes its types. That, and the fact that the REPL does things slightly differently, had me confused. If I instead declare a top-level bean

class Bean { val list: List[Int] = null }

then descriptorOf(classOf[Bean]).apply("list") give me exactly what I need. Thanks for the clarification!

@advorkovyy
Copy link
Collaborator

You can also use less verbose syntax:

descriptorOf[Bean]("list")

It does exactly the same. Well, almost. Nasty 'feature' of classOf[...] is that it returns only type erasure, without generic type arguments. In this particular case it doesn't matter since Bean has no type arguments, but in generic case it is better to use descriptorOf[Bean]. It relies on Manifest with full type information. Look at the examples in our documentation http://scalabeans.googlecode.com/

@christophercurrie
Copy link
Author

I would use that syntax except that this is for jackson-module-scala, and at the moment that I need to introspect the type all I have access to is the class object (and since core Jackson is written in Java it would be difficult to propagate the Manifest).

In practice I don't think it will be an issue but there may be some corner cases that will be difficult to support. I'm still in much better shape than before scalabeans, though, so many thanks again!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants