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

object.getClass is an error in annotation #2453

Open
scabug opened this issue Oct 7, 2009 · 16 comments
Open

object.getClass is an error in annotation #2453

scabug opened this issue Oct 7, 2009 · 16 comments
Labels
Milestone

Comments

@scabug
Copy link

@scabug scabug commented Oct 7, 2009

scala lib version: 2.8.0-SNAPSHOT (timestamp: 20091006.003811 buildNumber: 232)

I can't pass the class of an object to a (Java) annotation (for ex, this one: https://svn.apache.org/repos/asf/directory/apacheds/trunk/core-integ/src/main/java/org/apache/directory/server/core/integ/annotations/Factory.java )

The Factory annotation expects a Factory implementation, which is just class with a static method "newInstance", and so is done in Scala with an object.

In Java, I write: @Factory( MyFactory.class )

In scala, @Factory( classOf[MyFactory] ) won't work as MyFactory is an object and @Factory( MyFactory.getClass ) doesn't compile due to the error:

"annotation argument needs to be a constant; found: MyFactory.getClass"

I don't see any other way to pass the object's class as the annotation parameter.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Oct 7, 2009

Imported From: https://issues.scala-lang.org/browse/SI-2453?orig=1
Reporter: Francois Armand (fanf)
See #6259

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Oct 21, 2009

Paul LaCrosse (pjlacrosse) said:
I have a similar problem:

Using the Oracle Berkeley DB for Java, I get:

"annotation argument needs to be a constant; found: ONE_TO_ONE{}"

when using this annotation:

@SecondaryKey(relate = ONE_TO_ONE)

where "ONE_TO_ONE" was imported as:
import com.sleepycat.persist.model.Relationship.ONE_TO_ONE

Interestingly, this problem shows up only in the Eclipse plugin manifesting as the error icon against the line in the editor, but not under the problems views. It also does not generate an error from a command-line scalac compilation.

This is using the 2.8 nightly from 20091021.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Oct 21, 2009

Paul LaCrosse (pjlacrosse) said:
... ignore that question mark next to the SecondaryKey annotation... it is not part of the code and appears to be a part of the wiki formatting.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Nov 12, 2009

@lrytz said:
Hi Fanf,

the question is which Class object should be passed to the annotation. For top-level scala objects, the scala compiler generates two classfiles

  object o { def x = 1 }

you get

  • o.class, which has static methods forwarding to the methods of o$$, i.e.
  class o { static int x() { return o$$.MODULE$$.x(); } }
  • o$$.class, which contains the actual implementation of the object's methods. The static initializer creates an instance of o$$ and stores it in the MODULE$$ field
  class o$$ {
    o$$ MODULE$$ = new o$$;
    int x() { return 1; }
  }

I don't know what org.apache.directory.server.core.integ.annotations.Factory expects. If it wants static factory methods, we should pass the o class, not o$$.

However, calling o.getClass in scala returns

scala> o.getClass
res0: java.lang.Class[_] = class o$$

For nested objects, the additional classfile with static forwarders is not generated. Instead, a method is added to the containing class:

  class A { object p { def x = 1 } }

generates

  • A.class with
  class A {
    A$$p$$ p$$module = null;
    A$$p$$ p() {
      if (p$$module == null) { p$$module = new A$$p$$ };
      return A$$p$$;
    }
  }
  • A$$p$$.class with
  class A$$p$$ { int x() { return 1; } }

So in this case there doesn't exist any static methods which could be called.

Again, getClass returns the object A$$p$$:

scala> (new A).p.getClass
res0: java.lang.Class[_] = class A$$p$$

We cannot allow o.getClass to be a constant because it isn't. Maybe we could hack something because we know that objects are final.

I could allow classOf[o.type] and load the module class in this case (o$$), but I don't know if this helps in your case. I cannot load the class with the static forwarders (o) because this is only generated in the backend, and only for top-level objects.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Nov 12, 2009

Francois Armand (fanf) said:
Hum, that's much more complex that I thougth.
For my personnal use case, I just noticed that now, ApacheDS accept class and instance method for the Factory annotation, so on that regard, my problem is solved.

Regarding the general problem, without your explanations I would have say "load the class with the static forwarder", but it doesn't seems to be possible :)

I don't know what is the best second choice. Or perhaps, there is just not enought use cases to decide (as even mine isn't relevant anymore), and you could close the bug for now, waiting to have better example to know what to do.

Sorry for the time spend, and thanks for the explanations.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Aug 26, 2011

Hongxin Liang (honnix) said:
Sorry to bring this up again.

As an experiment, I tried to combine scala with powermock, but I met exactly the same problem described by this issue.

In order to mock a static class (object in scala), I need to write annotation @PrepareForTest(TheStaticClass.class), but this does not work as described.

My question is that whether there is a plan to fix it or this can only be left as one limitation of scala?

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Aug 27, 2011

Iskra Vitaly (iskra.vitaly) said:
As I understand, there are always 2 classes related to scala's object:

  1. The one having static methods implementations
  2. The one having instance methods delegating to corresponding statics

In some cases users of a object need to pass first class somewhere, in some second.
So why not make 2 distinct operators solely for objects instanceClassOf[] and staticClassOf[] to let the users to decide what do they need each time they need a class?

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Aug 27, 2011

Hongxin Liang (honnix) said:
Hmm, really good suggestion. There should be good reasons to get both the static and non-static class of object.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Sep 15, 2011

Francois Armand (fanf) said:
The URL given in the first message now leads to a 404. That one still works: https://svn.apache.org/repos/asf/directory/apacheds/tags/1.5.2/core-integ/src/main/java/org/apache/directory/server/core/integ/annotations/Factory.java

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Sep 11, 2012

@jsuereth said:
The inability to grab an object's class outside of the constructor is killing us here.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Sep 11, 2012

@retronym said:
I wonder, could {{classOf}} be rewritten these days as a macro? How about {{instanceClassOf}} / {{staticClassOf}}?

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jan 24, 2013

@retronym said:
https://groups.google.com/d/topic/scala-internals/D6LoxxxRbAA/discussion

scala> object O
defined module O

scala> def impl[T: c.WeakTypeTag](c: Context): c.Expr[Class[_]] = {import c.universe._; c.Expr[Class[_]](Literal(Constant(weakTypeOf[T])))}
impl: [T](c: scala.reflect.macros.Context)(implicit evidence$1: c.WeakTypeTag[T])c.Expr[Class[_]]

scala> def moduleClassOf[T <: Singleton]: Class[_] = macro impl[T]
moduleClassOf: [T <: Singleton]=> Class[_]

scala> moduleClassOf[O.type]
res5: Class[O.type] = class O$
@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Mar 15, 2013

@adriaanm said:
Un-assigning to foster work stealing, as announced in https://groups.google.com/forum/?fromgroups=#!topic/scala-internals/o8WG4plpNkw

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Jul 10, 2013

@adriaanm said:
Unassigning and rescheduling to M6 as previous deadline was missed.

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Oct 22, 2015

tenstriker said:
even referencing scala class from java annotations might give an error. I am getting type mismatch error when referencing scala class that implements interface required by jsr-303 @constraint annotation.
for detail: http://stackoverflow.com/questions/33266551/jsr-303-constraintvalidator-in-scala-with-spring-mvc

@scabug

This comment has been minimized.

Copy link
Author

@scabug scabug commented Oct 22, 2015

@soc said:
I think this ticket demonstrates an issue, but we should think into which direction it should take us and adapt the ticket accordingly.

Should we come up with a way to refer to a companion symbol type as a constant (like companionOf\[T\]) or look into making SomeObject.getClass work as a constant literal?

@scabug scabug added the annotations label Apr 7, 2017
@scabug scabug added this to the 2.13.0-RC1 milestone Apr 7, 2017
@adriaanm adriaanm modified the milestones: 2.13.0-RC1, Backlog Nov 13, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.