Uploaded image for project: 'Felix'
  1. Felix
  2. FELIX-2892

Get SCR annotations to work with Scala

    Details

    • Type: Improvement
    • Status: Closed
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: maven-scr-plugin-1.9.0
    • Component/s: SCR Tooling
    • Labels:
      None

      Description

      Currently the maven scr plugin doesn't work with scala, teh main reason for this is that the annotation have only source scope and the adding of bind-methods happe on a source rather than a bytecode level.

      1. Foo.class
        1 kB
        Reto Gmür

        Issue Links

          Activity

          Hide
          cziegeler Carsten Ziegeler added a comment -

          The annotations are only needed at build time - that's why they just have source for the scope.

          Show
          cziegeler Carsten Ziegeler added a comment - The annotations are only needed at build time - that's why they just have source for the scope.
          Hide
          cziegeler Carsten Ziegeler added a comment -

          Maybe you could explain this use case a little bit more ?

          Show
          cziegeler Carsten Ziegeler added a comment - Maybe you could explain this use case a little bit more ?
          Hide
          reto Reto Gmür added a comment -

          If the retention level is CLASS and the bind-methods are added in bytecode any language that runs on the jvm would be supported by the scr plugin. They would not be available at runtime.

          For a discussion see: http://mail-archives.apache.org/mod_mbox/felix-users/201011.mbox/%3CAANLkTikGW_9fjDt1dfPuOTWR9fQ50_XB7TBf3-3Z0Djf@mail.gmail.com%3E

          Show
          reto Reto Gmür added a comment - If the retention level is CLASS and the bind-methods are added in bytecode any language that runs on the jvm would be supported by the scr plugin. They would not be available at runtime. For a discussion see: http://mail-archives.apache.org/mod_mbox/felix-users/201011.mbox/%3CAANLkTikGW_9fjDt1dfPuOTWR9fQ50_XB7TBf3-3Z0Djf@mail.gmail.com%3E
          Hide
          schwitzkroko Jochen Fliedner added a comment -

          As of FELIX-3550 and version "maven-scr-plugin-1.8.0" etc. there is class retention and also ASM is used to extract the annotations from class files. As a problem for Scala remains that in a first step the maven plugin identifies the types from the project source folders *.java files. There is no java source code generated by the Scala compiler, so you won´t see any action.
          Btw some groovy guys seem happy already and switched their servlet from Java code to an annoted Groovy type: https://github.com/Citytechinc/cq5-groovy-console
          I think they let generate Java stubs by the "gmaven-plugin" and those can be used by the scr plugin.
          Would it be possible to make the class identifiction run on the maven project target folder?

          Show
          schwitzkroko Jochen Fliedner added a comment - As of FELIX-3550 and version "maven-scr-plugin-1.8.0" etc. there is class retention and also ASM is used to extract the annotations from class files. As a problem for Scala remains that in a first step the maven plugin identifies the types from the project source folders *.java files. There is no java source code generated by the Scala compiler, so you won´t see any action. Btw some groovy guys seem happy already and switched their servlet from Java code to an annoted Groovy type: https://github.com/Citytechinc/cq5-groovy-console I think they let generate Java stubs by the "gmaven-plugin" and those can be used by the scr plugin. Would it be possible to make the class identifiction run on the maven project target folder?
          Hide
          cziegeler Carsten Ziegeler added a comment -

          Actually the scanning is done in the target classes folder: the maven scr plugin feeds a list of Source objects into the generator, a source object contains a file object pointing to the source (so this would be the java or the scala file) and the class name. This class name is used to find the class using a class loader which includes the target/classes folder.
          So I think all we have to do, is to instruct the maven scr plugin to create source objects for scala source files and the class which is generated.

          Show
          cziegeler Carsten Ziegeler added a comment - Actually the scanning is done in the target classes folder: the maven scr plugin feeds a list of Source objects into the generator, a source object contains a file object pointing to the source (so this would be the java or the scala file) and the class name. This class name is used to find the class using a class loader which includes the target/classes folder. So I think all we have to do, is to instruct the maven scr plugin to create source objects for scala source files and the class which is generated.
          Hide
          schwitzkroko Jochen Fliedner added a comment -

          The problem is this preceeding identification of the information kept in the Source objects collection. This is done on the - or an aggregation of? - source folder(s) using "project.getCompileSourceRoots().iterator()".
          Class names are identified and in that some assumptions are hardcoded that are feasable only for Java sources:

          • that the eventual classes fqns always corresponds with the folder structure and the file name of the sources
          • that there is a "java" file extension
            When locally in the code i switch to "project.getBuild().getOutputDirectory()" and assume a file extension of length 5 - like in ".class" - to be tossed, it basically works fine. So obviously you can always use such assumptions at the output dir with its folder structure and class files.
            Especially with Scala there are some regarding problems like you can code multiple packages and types within one source file, but after compilation that should be fine.
            Generally it would not be necessary to have any source folders involved for the nature of the thing that is to be accomplished here, even when it adheres to maven best practices to do so.
          Show
          schwitzkroko Jochen Fliedner added a comment - The problem is this preceeding identification of the information kept in the Source objects collection. This is done on the - or an aggregation of? - source folder(s) using "project.getCompileSourceRoots().iterator()". Class names are identified and in that some assumptions are hardcoded that are feasable only for Java sources: that the eventual classes fqns always corresponds with the folder structure and the file name of the sources that there is a "java" file extension When locally in the code i switch to "project.getBuild().getOutputDirectory()" and assume a file extension of length 5 - like in ".class" - to be tossed, it basically works fine. So obviously you can always use such assumptions at the output dir with its folder structure and class files. Especially with Scala there are some regarding problems like you can code multiple packages and types within one source file, but after compilation that should be fine. Generally it would not be necessary to have any source folders involved for the nature of the thing that is to be accomplished here, even when it adheres to maven best practices to do so.
          Hide
          cziegeler Carsten Ziegeler added a comment -

          Processing class files is one thing, but being able to relate an error to the source is the other important feature. That's why we have this Source object which a) points to a source file and b) points to a class file to process.
          We can change the process how these source objects are constructred in any way, however we need a pointer to the source file.
          I guess it would be interesting in the scala case to get an error reported on the scala source as well.

          Show
          cziegeler Carsten Ziegeler added a comment - Processing class files is one thing, but being able to relate an error to the source is the other important feature. That's why we have this Source object which a) points to a source file and b) points to a class file to process. We can change the process how these source objects are constructred in any way, however we need a pointer to the source file. I guess it would be interesting in the scala case to get an error reported on the scala source as well.
          Hide
          cziegeler Carsten Ziegeler added a comment -

          Ok, how about this:
          Instead of scanning just the source tree, we scan both, source tree and class files. If we know the source, we create a source object with source and class file, if we just have a class, we create a source file with an "unknown" source object.
          Obviously this slows down the build process, so it would be nice if we could have some trigger for also scanning the classes directory. We could either make this configurable and have it off by default, or check for src/main/scala and/or src/main/scripts or something like that.

          WDYT?

          Show
          cziegeler Carsten Ziegeler added a comment - Ok, how about this: Instead of scanning just the source tree, we scan both, source tree and class files. If we know the source, we create a source object with source and class file, if we just have a class, we create a source file with an "unknown" source object. Obviously this slows down the build process, so it would be nice if we could have some trigger for also scanning the classes directory. We could either make this configurable and have it off by default, or check for src/main/scala and/or src/main/scripts or something like that. WDYT?
          Hide
          cziegeler Carsten Ziegeler added a comment -

          I finally found FELIX-509, which is the issue why we added include/exclude patterns - basically it boils down to bugs in QDox which we are not using anymore

          Show
          cziegeler Carsten Ziegeler added a comment - I finally found FELIX-509 , which is the issue why we added include/exclude patterns - basically it boils down to bugs in QDox which we are not using anymore
          Hide
          cziegeler Carsten Ziegeler added a comment -

          Added a new configuration
          <scanClasses>true</scanClasses>

          If this is set, the classes folder is searched instead.

          Please give it a try

          Show
          cziegeler Carsten Ziegeler added a comment - Added a new configuration <scanClasses>true</scanClasses> If this is set, the classes folder is searched instead. Please give it a try
          Hide
          reto Reto Gmür added a comment - - edited

          Great with <scanClasses>true</scanClasses> it works. The only thing I had to exclude the scr-annotation in the bundle plugin with <Import-Package>!org.apache.felix.scr.annotations, *</Import-Package>, or would there be a reason fro having the available in OSGi.

          Show
          reto Reto Gmür added a comment - - edited Great with <scanClasses>true</scanClasses> it works. The only thing I had to exclude the scr-annotation in the bundle plugin with <Import-Package>!org.apache.felix.scr.annotations, *</Import-Package>, or would there be a reason fro having the available in OSGi.
          Hide
          cziegeler Carsten Ziegeler added a comment -

          Thanks for testing!

          No, excluding the annotations is the right thing - especially as there is no bundle containing these classes.

          Show
          cziegeler Carsten Ziegeler added a comment - Thanks for testing! No, excluding the annotations is the right thing - especially as there is no bundle containing these classes.
          Hide
          reto Reto Gmür added a comment -

          Could you deploy the snapshot to the snapshot repository? And of course having a release soon would be great.

          Show
          reto Reto Gmür added a comment - Could you deploy the snapshot to the snapshot repository? And of course having a release soon would be great.
          Hide
          reto Reto Gmür added a comment -

          Can something be done to avoid having to exclude it manually?

          Show
          reto Reto Gmür added a comment - Can something be done to avoid having to exclude it manually?
          Hide
          cziegeler Carsten Ziegeler added a comment -

          I've deployed the snapshots and plan to cut a release next week.

          I'm not sure why you get these imports in your case, this doesn't happen when used with Java - the annotations have retention policy of class, so bnd shouldn't see them

          Show
          cziegeler Carsten Ziegeler added a comment - I've deployed the snapshots and plan to cut a release next week. I'm not sure why you get these imports in your case, this doesn't happen when used with Java - the annotations have retention policy of class, so bnd shouldn't see them
          Hide
          reto Reto Gmür added a comment -

          I'm having problems also at runtime, I'm getting the error:

          zz>val t = $[Foo]
          error: error while loading Foo, Missing dependency 'class org.apache.felix.scr.annotations.Component', required by org/apache/clerezza/jaxrs/stanbol/webfragements/Foo.class

          Foo.class is attached, Foo.scala looks as follows:

          package org.apache.clerezza.jaxrs.stanbol.webfragements

          import org.apache.felix.scr.annotations._

          @Component
          @Service
          class Foo {

          println("fooling")

          def bar()

          { var r = getClass.getResource("META-INF/MANIFEST.MF") println(r) }

          }

          Show
          reto Reto Gmür added a comment - I'm having problems also at runtime, I'm getting the error: zz>val t = $ [Foo] error: error while loading Foo, Missing dependency 'class org.apache.felix.scr.annotations.Component', required by org/apache/clerezza/jaxrs/stanbol/webfragements/Foo.class Foo.class is attached, Foo.scala looks as follows: package org.apache.clerezza.jaxrs.stanbol.webfragements import org.apache.felix.scr.annotations._ @Component @Service class Foo { println("fooling") def bar() { var r = getClass.getResource("META-INF/MANIFEST.MF") println(r) } }
          Hide
          cziegeler Carsten Ziegeler added a comment -

          Not sure who is giving out this message, however the released version of the annotations (1.7.0) are using class as the retention policy, so they are not loaded/required for usual Java applications.
          Maybe the scala runtime is doing something?

          Show
          cziegeler Carsten Ziegeler added a comment - Not sure who is giving out this message, however the released version of the annotations (1.7.0) are using class as the retention policy, so they are not loaded/required for usual Java applications. Maybe the scala runtime is doing something?
          Hide
          apanday Arjun Panday added a comment -

          for info, i'd filed a bug to scala a while ago about this issue:
          https://issues.scala-lang.org/browse/SI-4788
          The problem is the scala compiler retaining all annotations at runtime .

          I think bnd takes this into account and automatically adds
          Ignore-Package: aQute.bnd.annotation.component

          Show
          apanday Arjun Panday added a comment - for info, i'd filed a bug to scala a while ago about this issue: https://issues.scala-lang.org/browse/SI-4788 The problem is the scala compiler retaining all annotations at runtime . I think bnd takes this into account and automatically adds Ignore-Package: aQute.bnd.annotation.component
          Hide
          reto Reto Gmür added a comment -

          The error message occurs when I request a service by an interface defined in Scala. So it seems that these annotations have somehow become part of the interface.

          Show
          reto Reto Gmür added a comment - The error message occurs when I request a service by an interface defined in Scala. So it seems that these annotations have somehow become part of the interface.
          Hide
          cziegeler Carsten Ziegeler added a comment -

          Yes, as Arjun wrote, this is a bug in scala

          Show
          cziegeler Carsten Ziegeler added a comment - Yes, as Arjun wrote, this is a bug in scala
          Hide
          reto Reto Gmür added a comment -

          The problem with the import statements can be worked around with the Ignore-Pacakge directive. The problem with the service can be worked around by extracting the exposed interface to a trait or superclass that has no annotation.

          E.g. for the example above define a trait FooT with the bar method and expose this as service interface:

          @Component
          @Service(Array(classOf[FooT]))
          class Foo extends FooT {
          ...

          Show
          reto Reto Gmür added a comment - The problem with the import statements can be worked around with the Ignore-Pacakge directive. The problem with the service can be worked around by extracting the exposed interface to a trait or superclass that has no annotation. E.g. for the example above define a trait FooT with the bar method and expose this as service interface: @Component @Service(Array(classOf [FooT] )) class Foo extends FooT { ...

            People

            • Assignee:
              cziegeler Carsten Ziegeler
              Reporter:
              reto Reto Gmür
            • Votes:
              8 Vote for this issue
              Watchers:
              6 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development