Maybe we should also think a little bit more if 'Type' really is the
right interface to use.  Both Guice and CDI defines 'TypeLiteral'
classes.  Maybe we should do the same?

Best Regards,

/Andreas

2012-03-11 21:05, Andreas Jonsson skrev:
> Hi,
> 
> We must consider how we define the equality of RoleHints.  Different
> implementations of the interface ParameterizedType do not need to
> implement equals and hashValue consistently.  For instance, this lookup
> doesn't work at the moment:
> 
> Utils.getComponent(new ParameterizedType() {
>                 @Override
>                 public Type [] getActualTypeArguments() {
>                     Type [] args = {
>                         String.class
>                     };
>                     return args;
>                 }
> 
>                 @Override
>                 public Type getOwnerType() {
>                     return null;
>                 }
> 
>                 @Override
>                 public Type getRawType() {
>                     return DocumentReferenceResolver.class;
>                 }
>             });
> 
> At the same time, there is the backwards compliancy issue. This might be
> ok for RoleHint equality:
> 
>     /**
>      * Defines the equality of types.
>      *
>      * @param t1 operand for comparison.
>      * @param t2 operand for comparison.
>      * @return {\code true} if the roles should be considered equal.
>      */
>     private boolean typeEquals(Type t1, Type t2) {
> 
>         if (t1 instanceof ParameterizedType && t2 instanceof
> ParameterizedType) {
>             ParameterizedType pt1 = (ParameterizedType) t1;
>             ParameterizedType pt2 = (ParameterizedType) t2;
> 
>             Type [] args1 = pt1.getActualTypeArguments();
>             Type [] args2 = pt2.getActualTypeArguments();
> 
>             if (args1.length != args2.length) {
>                 return false;
>             }
> 
>             for (int i = 0; i < args1.length; i++) {
>                 if (!typeEquals(args1[i], args2[i])) {
>                     return false;
>                 }
>             }
>         } else if ((t1 instanceof Class && !(t2 instanceof Class))
>                 || (t2 instanceof Class && !(t1 instanceof Class))) {
>             /*
>              * For compliancy with legacy code.
>              *
>              * Looking up components using raw classes only
>              * matches components registered as raw classes, and a
>              * component registered as raw class can only be
>              * looked up using a raw class.
>              */
>             return false;
>         }
> 
>         Class c1 = ReflectionUtils.getTypeClass(t1);
>         Class c2 = ReflectionUtils.getTypeClass(t2);
> 
>         return c1.equals(c2);
>     }
> 
>     @Override
>     @SuppressWarnings("unchecked")
>     public boolean equals(Object obj)
>     {
>         if (this == obj) {
>             return true;
>         }
> 
>         if ((obj == null) || (obj.getClass() != this.getClass())) {
>             return false;
>         }
> 
>         RoleHint<T> rolehint = (RoleHint<T>) obj;
> 
>         return typeEquals(getRoleType(), rolehint.getRoleType())
>             && (getHint() == rolehint.getHint() || (getHint() != null &&
> getHint().equals(rolehint.getHint())));
>     }
> 
>     @Override
>     public int hashCode()
>     {
>         int hash = 8;
> 
>         hash = 31 * hash + (null == getRoleType() ? 0 :
> ReflectionUtils.getTypeClass(getRoleType()).hashCode());
>         hash = 31 * hash + (null == getHint() ? 0 : getHint().hashCode());
> 
>         return hash;
>     }
> 
> /Andreas
> 
> 
> 2012-03-06 14:51, Thomas Mortagne skrev:
>> It's committed.
>>
>> Would be nice to have comments on the new APIs (suggest better naming,
>> etc...). It's a very important API and we really need to have
>> something we are sure of before 4.0 final.
>>
>> On Mon, Mar 5, 2012 at 6:53 PM, Thomas Mortagne
>> <[email protected]> wrote:
>>> Hi guys,
>>>
>>> I'm almost done but there is one little detail left: for easier
>>> retro-compatibility I would like to introduce a new @Role annotation
>>> and deprecate the @ComponentRole annotation. The idea is that Role
>>> will "officially" take into account generic parameters while
>>> ComponentRole does not. That way no existing component role behavior
>>> will be broken or require crappy retro-compatibility like registering
>>> automatically both generic and non generic roles (what I started to do
>>> at first).
>>>
>>> On Thu, Mar 1, 2012 at 6:20 PM, Thomas Mortagne
>>> <[email protected]> wrote:
>>>> Hi devs,
>>>>
>>>> I recently modified component manager internals and changed the role
>>>> used as key in the map from Class to Type so that it properly make a
>>>> difference between Provider<Toto> and Provider<Titi> without the need
>>>> to generate a special hint.
>>>>
>>>> For the one not aware of what Type is lets say it's what Class is
>>>> extending. Among other things Type is also extended by
>>>> ParameterizedType which is interesting here because it basically
>>>> contain a Class with it's generic parameters (it also indicate if the
>>>> type in included in another one but we don't care in our case ;)).
>>>>
>>>> To summarize:
>>>> * Provider is a Class
>>>> * Provider<String> is ParameterizedType
>>>> and both are Type
>>>>
>>>> That said I would like to  change the whole ComponentManager and
>>>> related descriptors APIs to use Type as role instead of Class.
>>>>
>>>> = What it bring
>>>>
>>>> What it means is that it makes possible to cleanly represent a
>>>> Provider in which the generic type is meaningful right in the
>>>> ComponentDescriptor (right now the generic type is extract from the
>>>> implementation class when the provider is registered which is pretty
>>>> crappy) and simplify a lot the current implementation.
>>>>
>>>> But it also mean we could use this new "feature" for other components.
>>>> For example right now we have things like:
>>>>
>>>> @Component
>>>> public class DefaultStringDocumentReferenceResolver implements
>>>> DocumentReferenceResolver<String>
>>>>
>>>> and
>>>>
>>>> @Component
>>>> @Named("default/reference")
>>>> public class DefaultReferenceDocumentReferenceResolver implements
>>>> DocumentReferenceResolver<EntityReference>
>>>>
>>>> and injected by
>>>>
>>>> @Inject
>>>> DocumentReferenceResolver<String> resolver;
>>>>
>>>> and
>>>>
>>>> @Inject
>>>> @Named("default/reference")
>>>> DocumentReferenceResolver<EntityReference> resolver;
>>>>
>>>> Having Type used as role means that we could have:
>>>>
>>>> @Inject
>>>> DocumentReferenceResolver<String> resolver;
>>>>
>>>> and
>>>>
>>>> @Inject
>>>> DocumentReferenceResolver<EntityReference> resolver;
>>>>
>>>> = What it breaks
>>>>
>>>> So what's the catch ?
>>>>
>>>> Basically it would break any code that currently programmatically
>>>> register or unregister Provider since It would remove the current hack
>>>> to discover the Provider parameter (assuming that the
>>>> ComponentDescriptor now provide the complete role). But that's OK IMO
>>>> given that Provider support is very recent and I doubt it's a common
>>>> use case.
>>>>
>>>> We would obviously keep and deprecate all the existing APIs based on
>>>> Class which are pretty easy to implement since Class extends Type.
>>>> Even if removing them would not cause any issue when you build it's
>>>> not binary compatible since it's not the same method signature.
>>>>
>>>> So WDYT ?
>>>>
>>>> Here is my +1 and since we are starting a new major version it sounds
>>>> a good occasion so introduce such change.
>>>>
>>>> --
>>>> Thomas Mortagne
>>>
>>>
>>>
>>> --
>>> Thomas Mortagne
>>
>>
>>
> 

_______________________________________________
devs mailing list
[email protected]
http://lists.xwiki.org/mailman/listinfo/devs

Reply via email to