Discussion:
BasicComponentParameter doesn't work with parameterized types
Daniel Wellman
2008-12-02 01:21:25 UTC
Permalink
It looks like PicoContainer 2 from trunk does not allow specifying
BasicComponentParameters when the target parameter has a
generic/parameterized type. The following code example produces this
ClassCastException:


java.lang.ClassCastException:
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
at
org.picocontainer.parameters.BasicComponentParameter.resolveInstance(BasicComponentParameter.java:161)
at
org.picocontainer.injectors.SingleMemberInjector.getParameter(SingleMemberInjector.java:67)
at
org.picocontainer.injectors.SingleMemberInjector.getMemberArguments(SingleMemberInjector.java:53)
at
org.picocontainer.injectors.ConstructorInjector.getMemberArguments(ConstructorInjector.java:240)
at
org.picocontainer.injectors.ConstructorInjector$1.run(ConstructorInjector.java:199)
at
org.picocontainer.injectors.AbstractInjector$ThreadLocalCyclicDependencyGuard.observe(AbstractInjector.java:289)
at
org.picocontainer.injectors.ConstructorInjector.getComponentInstance(ConstructorInjector.java:229)
at
org.picocontainer.DefaultPicoContainer.getInstance(DefaultPicoContainer.java:573)
at
org.picocontainer.DefaultPicoContainer.getComponent(DefaultPicoContainer.java:537)
at
org.picocontainer.DefaultPicoContainer.getComponent(DefaultPicoContainer.java:514)
at
com.bostoncapital.stuyvesant.picocontainer.PicoAcceptanceTest.testCannot_Use_BasicComponentParameter_with_Generic_Type(PicoAcceptanceTest.java:152)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:40)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:90)


Here's the example:


public void testCannot_Use_BasicComponentParameter_with_Generic_Type() {
DefaultPicoContainer pico = new DefaultPicoContainer();

pico.addComponent(FictionFactory.class);
pico.addComponent(NonFictionFactory.class);
pico.addComponent("bookHelperUsingFiction", BookHelper.class, new
BasicComponentParameter(FictionFactory.class));

// This throws a java.lang.ClassCastException:
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
Object component = pico.getComponent("bookHelperUsingFiction");
assertNotNull(component);
}

public static class BookHelper {
BookFactory factory;

// The test above passes if BookFactory does not have a parameterized
type, e.g.
// if it's publicBookHelper(BookFactory newFactory) { ... }
public BookHelper(BookFactory newFactory) {
this.factory = newFactory;
}
}

public static interface BookFactory {
T build();
}

public static class FictionFactory implements BookFactory {
public Fiction build() {
return new Fiction();
}
}

public static class NonFictionFactory implements BookFactory {

public NonFiction build() {
return new NonFiction();
}
}

static class Fiction {
}

static class NonFiction {
}
--
View this message in context: http://www.nabble.com/BasicComponentParameter-doesn%27t-work-with-parameterized-types-tp20784248p20784248.html
Sent from the NanoContainer - PicoContainer - Users mailing list archive at Nabble.com.
Daniel Wellman
2008-12-02 01:43:13 UTC
Permalink
Reposting the code since the HTML formatting ate all the parameterized types.
Doh!


public void testCannot_Use_BasicComponentParameter_with_Generic_Type() {
DefaultPicoContainer pico = new DefaultPicoContainer();

pico.addComponent(FictionFactory.class);
pico.addComponent(NonFictionFactory.class);

// This throws a java.lang.ClassCastException:
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
pico.addComponent("bookHelperUsingFiction", BookHelper.class, new
BasicComponentParameter(FictionFactory.class));

Object component = pico.getComponent("bookHelperUsingFiction");
assertNotNull(component);
}

public static class BookHelper<T> {
BookFactory<T> factory;

// The test above passes if BookFactory does not have a parameterized
type, e.g.
// if it's publicBookHelper(BookFactory newFactory) { ... }
public BookHelper(BookFactory<T> newFactory) {
this.factory = newFactory;
}
}

public static interface BookFactory<T> {
T build();
}

public static class FictionFactory implements BookFactory<Fiction> {
public Fiction build() {
return new Fiction();
}
}

public static class NonFictionFactory implements BookFactory<NonFiction>
{

public NonFiction build() {
return new NonFiction();
}
}

static class Fiction {
}

static class NonFiction {
}
--
View this message in context: http://www.nabble.com/BasicComponentParameter-doesn%27t-work-with-parameterized-types-tp20784248p20784451.html
Sent from the NanoContainer - PicoContainer - Users mailing list archive at Nabble.com.


---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Paul Hammant
2008-12-02 14:33:00 UTC
Permalink
Hi Daniel,

Most likely we're not going to do the most fine-grained features of
Generics until PicoContainer 3.0 ( most of the API that refers to
Class will be changed to refer to Type instead, and we'll do some
capturing of potentially erased types on addComponent methods).

For now though, there is a very elegant PicoContainer 2.6+ way to do
what you want :

@Test
public void
testCan_Use_Provider_As_Workaround_For_with_Generic_Type() {
final DefaultPicoContainer pico = new DefaultPicoContainer();
pico.addComponent(FictionFactory.class);
pico.addComponent(NonFictionFactory.class);
pico.addAdapter(new ProviderAdapter() {
public Object getComponentKey() {
return "bookHelperUsingFiction";
}
// depend on what you like in the args for the provide
method......
public BookHelper provide(FictionFactory fictionFactory) {
return new BookHelper(fictionFactory);
}
});
Object component = pico.getComponent("bookHelperUsingFiction");
assertNotNull(component);
}


Regards,

- Paul
Post by Daniel Wellman
Reposting the code since the HTML formatting ate all the
parameterized types.
Doh!
public void
testCannot_Use_BasicComponentParameter_with_Generic_Type() {
DefaultPicoContainer pico = new DefaultPicoContainer();
pico.addComponent(FictionFactory.class);
pico.addComponent(NonFictionFactory.class);
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
pico.addComponent("bookHelperUsingFiction", BookHelper.class, new
BasicComponentParameter(FictionFactory.class));
Object component = pico.getComponent("bookHelperUsingFiction");
assertNotNull(component);
}
public static class BookHelper<T> {
BookFactory<T> factory;
// The test above passes if BookFactory does not have a
parameterized
type, e.g.
// if it's publicBookHelper(BookFactory newFactory) { ... }
public BookHelper(BookFactory<T> newFactory) {
this.factory = newFactory;
}
}
public static interface BookFactory<T> {
T build();
}
public static class FictionFactory implements BookFactory<Fiction> {
public Fiction build() {
return new Fiction();
}
}
public static class NonFictionFactory implements
BookFactory<NonFiction>
{
public NonFiction build() {
return new NonFiction();
}
}
static class Fiction {
}
static class NonFiction {
}
--
View this message in context: http://www.nabble.com/BasicComponentParameter-doesn%27t-work-with-parameterized-types-tp20784248p20784451.html
Sent from the NanoContainer - PicoContainer - Users mailing list archive at Nabble.com.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email
Paul Hammant
2008-12-02 15:49:45 UTC
Permalink
Yeah, you'll most likely have to make that anon-inner class non-anon,
and make it public. There's a dumbass JVM rule about methods being
inaccessible despite being public if the class containing them is
private (implicitly anon-inner ones are).

There's no setAccessible() that can be done via reflection, it would
have to be an ASM solution to allow more elegant anon-inner usage.

Regards,

- Paul
Post by Paul Hammant
Hi Daniel,
Most likely we're not going to do the most fine-grained features of
Generics until PicoContainer 3.0 ( most of the API that refers to
Class will be changed to refer to Type instead, and we'll do some
capturing of potentially erased types on addComponent methods).
For now though, there is a very elegant PicoContainer 2.6+ way to do
@Test
public void
testCan_Use_Provider_As_Workaround_For_with_Generic_Type() {
final DefaultPicoContainer pico = new DefaultPicoContainer();
pico.addComponent(FictionFactory.class);
pico.addComponent(NonFictionFactory.class);
pico.addAdapter(new ProviderAdapter() {
public Object getComponentKey() {
return "bookHelperUsingFiction";
}
// depend on what you like in the args for the provide
method......
public BookHelper provide(FictionFactory fictionFactory) {
return new BookHelper(fictionFactory);
}
});
Object component = pico.getComponent("bookHelperUsingFiction");
assertNotNull(component);
}
Regards,
- Paul
Post by Daniel Wellman
Reposting the code since the HTML formatting ate all the
parameterized types.
Doh!
public void
testCannot_Use_BasicComponentParameter_with_Generic_Type() {
DefaultPicoContainer pico = new DefaultPicoContainer();
pico.addComponent(FictionFactory.class);
pico.addComponent(NonFictionFactory.class);
sun.reflect.generics.reflectiveObjects.ParameterizedTypeImpl
pico.addComponent("bookHelperUsingFiction", BookHelper.class, new
BasicComponentParameter(FictionFactory.class));
Object component = pico.getComponent("bookHelperUsingFiction");
assertNotNull(component);
}
public static class BookHelper<T> {
BookFactory<T> factory;
// The test above passes if BookFactory does not have a
parameterized
type, e.g.
// if it's publicBookHelper(BookFactory newFactory) { ... }
public BookHelper(BookFactory<T> newFactory) {
this.factory = newFactory;
}
}
public static interface BookFactory<T> {
T build();
}
public static class FictionFactory implements BookFactory<Fiction> {
public Fiction build() {
return new Fiction();
}
}
public static class NonFictionFactory implements
BookFactory<NonFiction>
{
public NonFiction build() {
return new NonFiction();
}
}
static class Fiction {
}
static class NonFiction {
}
--
View this message in context: http://www.nabble.com/BasicComponentParameter-doesn%27t-work-with-parameterized-types-tp20784248p20784451.html
Sent from the NanoContainer - PicoContainer - Users mailing list archive at Nabble.com.
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
http://xircles.codehaus.org/manage_email
---------------------------------------------------------------------
To unsubscribe from this list, please visit:

http://xircles.codehaus.org/manage_email

Loading...