Announcement Announcement Module
Collapse

Spring Dynamic Modules forum decommissioned in favor of Eclipse Gemini Blueprint

With the official first release of Eclipse Gemini Blueprint shipped, the migration of the Spring Dynamic Modules code base to the Eclipse Foundation, as part of the Gemini project, has been completed.

As such, this forum has been decommissioned in favour of the Eclipse Gemini forums.
See more
See less
Annotation @ServiceReference on List Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Annotation @ServiceReference on List

    Hi,

    I try to inject a list of services on a spring bean, here is a snipset :

    @ServiceReference(cardinality = ServiceReferenceCardinality.C1__N)
    public void setInvoiceServices(java.util.List<InvoiceService> invoiceServices) {
    ...
    }

    I got a Illegal argument exception: Cannot infer type for collection-based reference [invoiceService]. This exception tells me that the method parameter
    isn't java.util.Collection compatible.

    Where it's intereseting is the Spring DM 1.2 class ServiceReferenceInjectionBeanPostProcessor line 226 :

    if (Collection.class.isAssignableFrom(params[0])) {
    throw new IllegalArgumentException("Cannot infer type for collection-based reference [" + beanName
    + "]");
    }

    Is it what we want or the contrary? Is it bugged?

  • #2
    It's probably a bug - can you please open an issue?
    Thanks,

    Comment


    • #3
      Issue tracker

      I created this issue OSGI-741

      Comment


      • #4
        Cool. Thanks - I'll try to schedule for the next release of the 1.2.x branch.

        Comment


        • #5
          Originally posted by dabder View Post
          Hi,

          I try to inject a list of services on a spring bean, here is a snipset :

          @ServiceReference(cardinality = ServiceReferenceCardinality.C1__N)
          public void setInvoiceServices(java.util.List<InvoiceService> invoiceServices) {
          ...
          }

          I got a Illegal argument exception: Cannot infer type for collection-based reference [invoiceService]. This exception tells me that the method parameter
          isn't java.util.Collection compatible.

          Where it's intereseting is the Spring DM 1.2 class ServiceReferenceInjectionBeanPostProcessor line 226 :

          if (Collection.class.isAssignableFrom(params[0])) {
          throw new IllegalArgumentException("Cannot infer type for collection-based reference [" + beanName
          + "]");
          }

          Is it what we want or the contrary? Is it bugged?
          It's not a bug. Java doesn't give you enough information about the generic type at runtime to be able to infer whether the type you are using is compatible. A generic Collection is not compatible (or at least not useful since it will only contain proxies of type Object), you need to tell it the interface type of the references that will be returned by the collection by setting the serviceType in the annotation.

          Comment


          • #6
            A bug

            The first argument of my method is a java.util.List.

            Java is able to test the class of this object independently of the generics. Java doesn't know what kind of objects the list contains, but Java knows it's a List.

            It's what is done here (params[0] is a List) :

            if (Collection.class.isAssignableFrom(params[0])) {
            throw new IllegalArgumentException("Cannot infer type for collection-based reference [" + beanName
            + "]");
            }

            In my opinion, this test (if) has to be inverted.

            Didier.

            Comment


            • #7
              Originally posted by dabder View Post
              The first argument of my method is a java.util.List.

              Java is able to test the class of this object independently of the generics. Java doesn't know what kind of objects the list contains, but Java knows it's a List.

              It's what is done here (params[0] is a List) :

              if (Collection.class.isAssignableFrom(params[0])) {
              throw new IllegalArgumentException("Cannot infer type for collection-based reference [" + beanName
              + "]");
              }

              In my opinion, this test (if) has to be inverted.

              Didier.
              The code first checks if the type is implied, if it is explicit it never gets this far. This code is checking method parameter types, not actual arguments so it can't know the type of the object that will be passed in because that hasn't happened yet. So my original assertion still stands.

              Comment


              • #8
                A bug

                OK, i read angain the code, you are right.

                I thought that it was the same principle as JPA injection, like this :

                ----
                @Entity
                public class Window {

                @OneToMany(cascade = { CascadeType.REMOVE }, fetch = FetchType.EAGER)
                @JoinColumn(name = "window_id")
                private Map<String, Preference> preferences = new HashMap<String, Preference>();
                -----

                Preference is an other entity, i don't have to tell JPA the object type referenced here.

                It would be natural to code in a such way with SPring DM. I don't know how hibernate is able to analyse Generics because they are cleared in the byte code.

                Do you now more about this?

                Comment


                • #9
                  Originally posted by dabder View Post
                  OK, i read angain the code, you are right.

                  I thought that it was the same principle as JPA injection, like this :

                  ----
                  @Entity
                  public class Window {

                  @OneToMany(cascade = { CascadeType.REMOVE }, fetch = FetchType.EAGER)
                  @JoinColumn(name = "window_id")
                  private Map<String, Preference> preferences = new HashMap<String, Preference>();
                  -----

                  Preference is an other entity, i don't have to tell JPA the object type referenced here.

                  It would be natural to code in a such way with SPring DM. I don't know how hibernate is able to analyse Generics because they are cleared in the byte code.

                  Do you now more about this?
                  I don't know enough about JPA to comment. Its possible they are inferring the type from the DB table also they may not be using proxies so don't have to decide ahead of time the type of thing that is to be returned.

                  The limitation here is really in Spring DM/Java, I have tried many times with Costin to come up with a scheme that is more intuitive, but because you need to know the type of the proxy a-priori its really not possible. This is because you are dealing with a dynamic collection - even if you greedily proxied based on the initial types you saw, there is no guarantee that they would be the same at a later date, breaking the type-safety of the proxy.

                  Comment


                  • #10
                    It's possible !

                    I was curious to know how hibernate (JPA) was able to determinate at runtime the generic type of a setter like :

                    void setSomething(Collection<Window> windows)

                    With JPA spec, it's not mandatory to specify the type of Entity targeted.

                    So I studied the source code of Hibernate to find out. I thought like you that generics are lost on compiled file (class), but it's not true for methods. With Java reflexion, it's possible to know the parametrized type of a argument.

                    I coded a simple Java class to validate this :

                    ----------------------
                    public class Test {


                    public static void main(String[] args) throws Exception {

                    Method method = Test.class.getDeclaredMethod("inject", Collection.class);
                    Type type = method.getGenericParameterTypes()[0]; // first argument

                    if(type instanceof ParameterizedType) {
                    Class clazz = (Class) ((ParameterizedType)type).getActualTypeArguments()[0]; // first type arg
                    System.out.println(clazz.getName());
                    }
                    }

                    private void inject(Collection<Inner> inners) {}
                    }

                    class Inner {}

                    --------------------------

                    So finally, I'm agree, my request isn't a bug. It's getting a improvement request.

                    Is it possible to improve Spring DM annotation to be able to detect the Generic type of Collection arguments like JPA?

                    Thanks.

                    Comment


                    • #11
                      dabder, the best way to get things fixed or/and improved is to raise an issue w/ as much information as possible.

                      Thanks,

                      Comment


                      • #12
                        Create an issue

                        Is has been already done : OSGI-741

                        Regards

                        Comment

                        Working...
                        X