4 Replies Latest reply on Oct 15, 2012 4:07 PM by pgrillo

    @New creates incorrectly cast class?

    pgrillo

      Consider the next 3 classes.

       

       

      @Alternative

      public  class Vehicle<T extends Motor> implements  Serializable {

       

      }

       

      @ConversationScoped

      public class Chevy extends Vehicle<V8> implements Serializeable {

       

      }

       

       

      @ConversationScoped

      public class ParkingLot implements Serializeable{

      @Inject Vehicle conversationVehicle;

      @Inject @New Vehicle instanceVehicle;

       

      public Vehicle getInstanceVehicle(){

      return instanceVehicle;

      }

       

       

      The problem is as follows:

       

      • There is only one Alternative to Vehicle above, and that is Chevy.
      • Generally i have a conversationally scoped Vehicle works well.
      • However, in this ParkingLot class, i need both the conversationally scoped Vehicle and new Instance of the same class.  I'll be moving stuff between them.

       

       

      However, after the above injections in ParkingLot, i get proxies cast differently.

      When injecting with @New, i get a Vehicle Proxy.

       

       

      Vehicle$Proxy$_$$_WeldClientProxy  (instanceVehicle)

      Chevy$Proxy$_$$_WeldClientProxy    (conversationVehicle)

       

       

      This is very problematic the object is then referenced by pages that expect Chevy Methods in them and we get errors when accessing from EL etc.

       

       

      Bottom line is this.  Whether i inject with or without @New should i not get the same proxy/class.  All i want is a

      a dependent instance.

       

      I have not figured out how to solve this problem.  I'm open to making calls into the bean manager if needed, or creating a producer.  However, it would seem to

      me that both of those injections should give me an instance of a Chevy.  Note, i also make Vehicle Abstract to see if i could get it to work.  @New still

      returned a proxied Vehicle class...

       

      Is this a Weld Bug?  Has anybody seen this?  Am i doing something wrong?

        • 1. Re: @New creates incorrectly cast class?
          jharting

          There's something wrong with your code. If you want to call Chevy methods on the object, why don't you declare your injection points as @Inject Chevy?

           

          A client proxy is only required to implement the requested type. Weld does usually use proxies that implement all the bean types but that should not be relied on. It's not a bug in Weld.

          • 2. Re: @New creates incorrectly cast class?
            pgrillo

            Perhaps i didn't make myself clear enough.

             

            ParkingLot class is a generic class that can't and shouldn't know what type of Vehicle will be injected.  After all, that is the reason for "alternative".  If i replace chevy with ford as an alternative (there are many ways to do that), then what will/should get injected is Ford.

             

            The code referenced

            @Inject Vehicle conversationVehicle;

            @Inject @New Vehicle instanceVehicle;

             

             

            All of our JSF ui/xhtml pages that know about chevies,  access parkingLog.vehicle and have access to chevy methods.  If this were not the case, it would be impossible to build a JSF application of this kind using CDI.  In fact, the first line above works perfectly, and it is what we use.

             

            However, when i add the "@New" annotation to get a dependent instance, Weld returns a totally different proxy, and it does not proxy chevy.

             

            So, if what you are telling me is that i got "lucky" with the first injection and i can never count on injecting an alternative class/object and expecting that the methods in that class will NOT be available to jsf UI, it would seem to me that there is a big problem here.

             

            I've been meaning (and will) switch to openwebbeans and see if there is a difference.  I believe this to be a bug.

             

            -- on a different not --

            But then, i have not been happy with CDIs shortcomings.  This would be one of them.  the other one is the inability to inject @New objects after construction of a class.  Example of this would simply be an Order Line Item.  When the user adds a line item to an order, i wish to add a new one.  If it is a CDI bean, i have not found how to do this.  I have been told, this can't be done.  Thus, this forces me to deal with "two" kinds of java objects.  Those that are CDI/Managed and those that are not, because CDI can't handle it.  Which means that those beans that are not CDI managed (the line item bean), in turn, cannot inject container based beans. All of this is very assymetrical, particularly if one is trying to create an architectural framework for 20 engineers and have to explain to them that there are two ways beans get created and have them figure out when to use container created beans, when not to.

             

            CDI has many strengths, and is very powerful.  But the inability to create a java object dynamically (at runtime, after construction) is pretty weak - as it is something that is done all the time...

            • 3. Re: @New creates incorrectly cast class?
              jharting

              I see a conflict between "ParkingLot class is a generic class that can't and shouldn't know what type of Vehicle will be injected" and "All of our JSF ui/xhtml pages that know about chevies,  access parkingLog.vehicle and have access to chevy methods".

               

              If your ParkingLot is really generic you should not assume Chevy methods to be present on ParkingLot.vehicle. What you probably want is to use a type parameter on ParkingLot e.g. ParkingLot<T extends Vehicle> in which case the @New bean would work as expected.

               

              Alternatively, you could specify the @New bean class explicitly e.g. @Inject @New(Chevy.class) Vehicle vehicle.

               

              As for the other topic it would be best if you create a separate thread for that. I think your problem could be easily resovled using a combination of @New and Instance.

              • 4. Re: @New creates incorrectly cast class?
                pgrillo

                I appreciate time in responding to this.

                 

                We are a company that is responsible for upwards of 12 independent applications that share base code througout - this includes both XHTML and java.  We have been doing this for a long time.

                 

                ParkingLot and Chevy were sort of made up terms to try to describe my problem.  Nonetheless, i believe that it is accurate.

                 

                Our XHTML code, in particular, is a mix of generic and product specific. So, we will have a "parkinglotbean" which is accessed by both generic and nongeneric xhtml depending on the context of the product.

                 

                So, some xhtml will bind to parkingLotBean.chevyMethod and generic xhtml will bind to parkingLogBean.genericMethod.

                 

                In all cases, we must have a single bean, we must name the bean with a generic name.  We use this througout our system with no problems.  We might have a VehicleBean, in which 80% of our xhtml accesses generic methods, and the other 20% of our product specific code might bind to a value of vehicleBean.specific.

                 

                So, we must always inject the generic class, but we have had no problems with EL expressions handling and finding the specific methods in the alternative subclass UNTIL, i required to use the @New annotation.

                 

                Note:

                @Inject Vehicle conversationVehicle;

                @Inject @New Vehicle instanceVehicle;

                 

                the first injection injects a ChevyProxy, but the second injection injects a Vehicle Proxy.  In the case of the use of @Altenative, WELD/CODI knows specifically what class must be injected there, because if it were ambiguous, the system would faile to start.  So, yes, it creates a proxy - but it should create a ChevyProxy.  And it does, in the first line, but when using @New, it doesn't.

                I believe this is a bug, i don't  understand how the system could not know it is a chevy, when it requires to know that it is a chevy when the system comes up...

                 

                 

                Again, thank you for you time, and i will either open anothe thread for the other issue, or look into your hints.  I did post this other issue before in another forum, and i was told that all injected beans are "singletonish".    I could try using @New, but there is no syntax or semantics that would allow me to use that annotation inside of a method.  Injections occur at object construction time, and i don't and can't see an example of a way to inject a new bean in a loop (for example).  User asks for 2 more line items, and i dynamically create two container objects.  I'm guessing the only possible approach here is to obtain a reference to the bean manager and look for an answer directly there, or possibly extend it.