Discussion:
[seam-dev] CDI with generic class and the hell of type erasure.
José Rodolfo Freitas
2011-12-06 19:13:20 UTC
Permalink
Hey guys, how you doing?

I'm trying to achieve something that might be impossible, but before
concluding that, I'd like to ask you, CDI gurus!

I have the following class:

public class Foo<T> {

public TypedQuery<T> getQuery(){

}

}

As you can Imagine, inside my getQuery method, I'd have to use "T.class" to
make it TypedQuery. which is impossible due java generics type erasure.

so I'd have to build a private field to hold the t.class for me.

public class Foo<T> {

private Class<T> klass;

public TypedQuery<T> getQuery(){

}

public void setKlass(Class<T> klass){
this.klass = klass;
}
}

The problem is that forcing this 'setKlass' feels very ugly to the api, and
it's not very error prone, since one could easily forget to set this
configuration.

So I had an Idea: force the setKlass inside the constructor:

public class Foo<T> {

private Class<T> klass;

public Foo(Class<T> klass){
this.klass = klass;
}

public TypedQuery<T> getQuery(){

}

}

Unfortunatelly, this breaks cdi, since it cannot inject it anymore. At
least AFAIK.

So, is there a way out of this? maybe using a secret solder feature?
Jason Porter
2011-12-06 19:26:21 UTC
Permalink
I don't know of any, Stuart or others may have some thoughts though.

On Tue, Dec 6, 2011 at 12:13, José Rodolfo Freitas <
Post by José Rodolfo Freitas
Hey guys, how you doing?
I'm trying to achieve something that might be impossible, but before
concluding that, I'd like to ask you, CDI gurus!
public class Foo<T> {
public TypedQuery<T> getQuery(){
}
}
As you can Imagine, inside my getQuery method, I'd have to use "T.class"
to make it TypedQuery. which is impossible due java generics type erasure.
so I'd have to build a private field to hold the t.class for me.
public class Foo<T> {
private Class<T> klass;
public TypedQuery<T> getQuery(){
}
public void setKlass(Class<T> klass){
this.klass = klass;
}
}
The problem is that forcing this 'setKlass' feels very ugly to the api,
and it's not very error prone, since one could easily forget to set this
configuration.
public class Foo<T> {
private Class<T> klass;
public Foo(Class<T> klass){
this.klass = klass;
}
public TypedQuery<T> getQuery(){
}
}
Unfortunatelly, this breaks cdi, since it cannot inject it anymore. At
least AFAIK.
So, is there a way out of this? maybe using a secret solder feature?
_______________________________________________
seam-dev mailing list
https://lists.jboss.org/mailman/listinfo/seam-dev
--
Jason Porter
http://lightguard-jp.blogspot.com
http://twitter.com/lightguardjp

Software Engineer
Open Source Advocate
Author of Seam Catch - Next Generation Java Exception Handling

PGP key id: 926CCFF5
PGP key available at: keyserver.net, pgp.mit.edu
xsalefter
2011-12-06 21:51:50 UTC
Permalink
Hi all..

I'm not sure whether my comment is help you or not, but I ever thinking about this some time ago, and may be could be archived by something like:

public class Foo<T> {
  private Class<T> clazz;
  
  @Inject
  public Foo(Class<T> c) {
    this.clazz = c;
  }
}

And by using custom qualifier, creating instance of Foo is just like:
@InjectConstructor(Blah.class)

private Foo<Blah> foo;

Am I missing something?


Thanks,
xsalefter
Post by José Rodolfo Freitas
Hey guys, how you doing?
I'm trying to achieve something that might be impossible, but before concluding that, I'd like to ask you, CDI gurus!
public class Foo<T> {
    public TypedQuery<T> getQuery(){
    }
}
As you can Imagine, inside my getQuery method, I'd have to use "T.class" to make it TypedQuery. which is impossible due java generics type erasure.
so I'd have to build a private field to hold the t.class for me.
public class Foo<T> {
    private Class<T> klass;
    public TypedQuery<T> getQuery(){
    }
    
    public void setKlass(Class<T> klass){
        this.klass = klass;
    }
}
The problem is that forcing this 'setKlass' feels very ugly to the api, and it's not very error prone, since one could easily forget to set this configuration.
public class Foo<T> {
    private Class<T> klass;
    
    public Foo(Class<T> klass){
        this.klass = klass;
    }
    public TypedQuery<T> getQuery(){
    }
}
Unfortunatelly, this breaks cdi, since it cannot inject it anymore. At least AFAIK.
So, is there a way out of this? maybe using a secret solder feature?
Ales Justin
2011-12-06 22:45:47 UTC
Permalink
You could do something like this:

@SuppressWarnings({"unchecked"})
@Produces
public GenericQuery injectClass(InjectionPoint ip) {
Annotated annotated = ip.getAnnotated();
Class clazz = Object.class;
Type type = annotated.getBaseType();
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
clazz = (Class) pt.getActualTypeArguments()[0];
}
return new GenericQuery(clazz);
}

--

@Inject
GenericQuery<String> gqs;
@Inject
GenericQuery<Number> gqn;

--

System.out.println("GQS: " + gqs.getClazz());
System.out.println("GQN: " + gqn.getClazz());

--

GQS: class java.lang.String
GQN: class java.lang.Number

--

https://github.com/alesj/cdi-arq-workshop/commit/64860f15197be40a7714dfd8a7da931c1db11411

HTH

-Ales
Post by José Rodolfo Freitas
Hey guys, how you doing?
I'm trying to achieve something that might be impossible, but before concluding that, I'd like to ask you, CDI gurus!
public class Foo<T> {
public TypedQuery<T> getQuery(){
}
}
As you can Imagine, inside my getQuery method, I'd have to use "T.class" to make it TypedQuery. which is impossible due java generics type erasure.
so I'd have to build a private field to hold the t.class for me.
public class Foo<T> {
private Class<T> klass;
public TypedQuery<T> getQuery(){
}
public void setKlass(Class<T> klass){
this.klass = klass;
}
}
The problem is that forcing this 'setKlass' feels very ugly to the api, and it's not very error prone, since one could easily forget to set this configuration.
public class Foo<T> {
private Class<T> klass;
public Foo(Class<T> klass){
this.klass = klass;
}
public TypedQuery<T> getQuery(){
}
}
Unfortunatelly, this breaks cdi, since it cannot inject it anymore. At least AFAIK.
So, is there a way out of this? maybe using a secret solder feature?
_______________________________________________
seam-dev mailing list
https://lists.jboss.org/mailman/listinfo/seam-dev
Jason Porter
2011-12-06 22:55:39 UTC
Permalink
Nice solution Ales, wish I'd thought of it :)
Post by Ales Justin
@SuppressWarnings({"unchecked"})
@Produces
public GenericQuery injectClass(InjectionPoint ip) {
Annotated annotated = ip.getAnnotated();
Class clazz = Object.class;
Type type = annotated.getBaseType();
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
clazz = (Class) pt.getActualTypeArguments()[0];
}
return new GenericQuery(clazz);
}
--
@Inject
GenericQuery<String> gqs;
@Inject
GenericQuery<Number> gqn;
--
System.out.println("GQS: " + gqs.getClazz());
System.out.println("GQN: " + gqn.getClazz());
--
GQS: class java.lang.String
GQN: class java.lang.Number
--
https://github.com/alesj/cdi-arq-workshop/commit/64860f15197be40a7714dfd8a7da931c1db11411
HTH
-Ales
Hey guys, how you doing?
I'm trying to achieve something that might be impossible, but before
concluding that, I'd like to ask you, CDI gurus!
public class Foo<T> {
public TypedQuery<T> getQuery(){
}
}
As you can Imagine, inside my getQuery method, I'd have to use "T.class"
to make it TypedQuery. which is impossible due java generics type erasure.
so I'd have to build a private field to hold the t.class for me.
public class Foo<T> {
private Class<T> klass;
public TypedQuery<T> getQuery(){
}
public void setKlass(Class<T> klass){
this.klass = klass;
}
}
The problem is that forcing this 'setKlass' feels very ugly to the api,
and it's not very error prone, since one could easily forget to set this
configuration.
public class Foo<T> {
private Class<T> klass;
public Foo(Class<T> klass){
this.klass = klass;
}
public TypedQuery<T> getQuery(){
}
}
Unfortunatelly, this breaks cdi, since it cannot inject it anymore. At least AFAIK.
So, is there a way out of this? maybe using a secret solder feature?
_______________________________________________
seam-dev mailing list
https://lists.jboss.org/mailman/listinfo/seam-dev
_______________________________________________
seam-dev mailing list
https://lists.jboss.org/mailman/listinfo/seam-dev
--
Jason Porter
http://lightguard-jp.blogspot.com
http://twitter.com/lightguardjp

Software Engineer
Open Source Advocate
Author of Seam Catch - Next Generation Java Exception Handling

PGP key id: 926CCFF5
PGP key available at: keyserver.net, pgp.mit.edu
José Rodolfo Freitas
2011-12-06 23:29:39 UTC
Permalink
thatŽs an awesome solution Ales!
I didnŽt thought that I could obtain the parametizedType that way!
Testing this will be my first task tomorrow morning.

thank you all for your ideas.
Post by Jason Porter
Nice solution Ales, wish I'd thought of it :)
Post by Ales Justin
@SuppressWarnings({"unchecked"})
@Produces
public GenericQuery injectClass(InjectionPoint ip) {
Annotated annotated = ip.getAnnotated();
Class clazz = Object.class;
Type type = annotated.getBaseType();
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
clazz = (Class) pt.getActualTypeArguments()[0];
}
return new GenericQuery(clazz);
}
--
@Inject
GenericQuery<String> gqs;
@Inject
GenericQuery<Number> gqn;
--
System.out.println("GQS: " + gqs.getClazz());
System.out.println("GQN: " + gqn.getClazz());
--
GQS: class java.lang.String
GQN: class java.lang.Number
--
https://github.com/alesj/cdi-arq-workshop/commit/64860f15197be40a7714dfd8a7da931c1db11411
HTH
-Ales
Hey guys, how you doing?
I'm trying to achieve something that might be impossible, but before
concluding that, I'd like to ask you, CDI gurus!
public class Foo<T> {
public TypedQuery<T> getQuery(){
}
}
As you can Imagine, inside my getQuery method, I'd have to use "T.class"
to make it TypedQuery. which is impossible due java generics type erasure.
so I'd have to build a private field to hold the t.class for me.
public class Foo<T> {
private Class<T> klass;
public TypedQuery<T> getQuery(){
}
public void setKlass(Class<T> klass){
this.klass = klass;
}
}
The problem is that forcing this 'setKlass' feels very ugly to the api,
and it's not very error prone, since one could easily forget to set this
configuration.
public class Foo<T> {
private Class<T> klass;
public Foo(Class<T> klass){
this.klass = klass;
}
public TypedQuery<T> getQuery(){
}
}
Unfortunatelly, this breaks cdi, since it cannot inject it anymore. At least AFAIK.
So, is there a way out of this? maybe using a secret solder feature?
_______________________________________________
seam-dev mailing list
https://lists.jboss.org/mailman/listinfo/seam-dev
_______________________________________________
seam-dev mailing list
https://lists.jboss.org/mailman/listinfo/seam-dev
--
Jason Porter
http://lightguard-jp.blogspot.com
http://twitter.com/lightguardjp
Software Engineer
Open Source Advocate
Author of Seam Catch - Next Generation Java Exception Handling
PGP key id: 926CCFF5
PGP key available at: keyserver.net, pgp.mit.edu
José Rodolfo Freitas
2011-12-07 12:21:10 UTC
Permalink
Ales and All,

when

@Inject
GenericQuery<String> gqs;

my producer do:

new GenericQuery(clazz)

And then @Inject inside GenericQuery does not work (since I'm using new).

What's the best approach in this situation?

Using BeanManagerProvider.getInstance() inside GenericQuery constructor to
provide instances for the objects I want to inject?


On Tue, Dec 6, 2011 at 9:29 PM, José Rodolfo Freitas <
Post by José Rodolfo Freitas
thatŽs an awesome solution Ales!
I didnŽt thought that I could obtain the parametizedType that way!
Testing this will be my first task tomorrow morning.
thank you all for your ideas.
Post by Jason Porter
Nice solution Ales, wish I'd thought of it :)
Post by Ales Justin
@SuppressWarnings({"unchecked"})
@Produces
public GenericQuery injectClass(InjectionPoint ip) {
Annotated annotated = ip.getAnnotated();
Class clazz = Object.class;
Type type = annotated.getBaseType();
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
clazz = (Class) pt.getActualTypeArguments()[0];
}
return new GenericQuery(clazz);
}
--
@Inject
GenericQuery<String> gqs;
@Inject
GenericQuery<Number> gqn;
--
System.out.println("GQS: " + gqs.getClazz());
System.out.println("GQN: " + gqn.getClazz());
--
GQS: class java.lang.String
GQN: class java.lang.Number
--
https://github.com/alesj/cdi-arq-workshop/commit/64860f15197be40a7714dfd8a7da931c1db11411
HTH
-Ales
Hey guys, how you doing?
I'm trying to achieve something that might be impossible, but before
concluding that, I'd like to ask you, CDI gurus!
public class Foo<T> {
public TypedQuery<T> getQuery(){
}
}
As you can Imagine, inside my getQuery method, I'd have to use "T.class"
to make it TypedQuery. which is impossible due java generics type erasure.
so I'd have to build a private field to hold the t.class for me.
public class Foo<T> {
private Class<T> klass;
public TypedQuery<T> getQuery(){
}
public void setKlass(Class<T> klass){
this.klass = klass;
}
}
The problem is that forcing this 'setKlass' feels very ugly to the api,
and it's not very error prone, since one could easily forget to set this
configuration.
public class Foo<T> {
private Class<T> klass;
public Foo(Class<T> klass){
this.klass = klass;
}
public TypedQuery<T> getQuery(){
}
}
Unfortunatelly, this breaks cdi, since it cannot inject it anymore. At least AFAIK.
So, is there a way out of this? maybe using a secret solder feature?
_______________________________________________
seam-dev mailing list
https://lists.jboss.org/mailman/listinfo/seam-dev
_______________________________________________
seam-dev mailing list
https://lists.jboss.org/mailman/listinfo/seam-dev
--
Jason Porter
http://lightguard-jp.blogspot.com
http://twitter.com/lightguardjp
Software Engineer
Open Source Advocate
Author of Seam Catch - Next Generation Java Exception Handling
PGP key id: 926CCFF5
PGP key available at: keyserver.net, pgp.mit.edu
Ales Justin
2011-12-07 12:33:38 UTC
Permalink
To reply, what we already discussed on irc.

This will do it:

Class<RequestHandler> clazz = (Class<RequestHandler>) tmp;

InjectionTarget<RequestHandler> it = manager.createInjectionTarget(manager.createAnnotatedType(clazz));
CreationalContext<RequestHandler> cc = manager.createCreationalContext(null);
// handler = it.produce(cc); // no need for this, if you already have an instance
it.inject(handler, cc);


https://github.com/capedwarf/capedwarf-green/blob/master/server-api/src/main/java/org/jboss/capedwarf/server/api/servlet/WeldServlet.java
Post by José Rodolfo Freitas
Ales and All,
when
@Inject
GenericQuery<String> gqs;
new GenericQuery(clazz)
What's the best approach in this situation?
Using BeanManagerProvider.getInstance() inside GenericQuery constructor to provide instances for the objects I want to inject?
thatŽs an awesome solution Ales!
I didnŽt thought that I could obtain the parametizedType that way!
Testing this will be my first task tomorrow morning.
thank you all for your ideas.
Nice solution Ales, wish I'd thought of it :)
@SuppressWarnings({"unchecked"})
@Produces
public GenericQuery injectClass(InjectionPoint ip) {
Annotated annotated = ip.getAnnotated();
Class clazz = Object.class;
Type type = annotated.getBaseType();
if (type instanceof ParameterizedType) {
ParameterizedType pt = (ParameterizedType) type;
clazz = (Class) pt.getActualTypeArguments()[0];
}
return new GenericQuery(clazz);
}
--
@Inject
GenericQuery<String> gqs;
@Inject
GenericQuery<Number> gqn;
--
System.out.println("GQS: " + gqs.getClazz());
System.out.println("GQN: " + gqn.getClazz());
--
GQS: class java.lang.String
GQN: class java.lang.Number
--
https://github.com/alesj/cdi-arq-workshop/commit/64860f15197be40a7714dfd8a7da931c1db11411
HTH
-Ales
Post by José Rodolfo Freitas
Hey guys, how you doing?
I'm trying to achieve something that might be impossible, but before concluding that, I'd like to ask you, CDI gurus!
public class Foo<T> {
public TypedQuery<T> getQuery(){
}
}
As you can Imagine, inside my getQuery method, I'd have to use "T.class" to make it TypedQuery. which is impossible due java generics type erasure.
so I'd have to build a private field to hold the t.class for me.
public class Foo<T> {
private Class<T> klass;
public TypedQuery<T> getQuery(){
}
public void setKlass(Class<T> klass){
this.klass = klass;
}
}
The problem is that forcing this 'setKlass' feels very ugly to the api, and it's not very error prone, since one could easily forget to set this configuration.
public class Foo<T> {
private Class<T> klass;
public Foo(Class<T> klass){
this.klass = klass;
}
public TypedQuery<T> getQuery(){
}
}
Unfortunatelly, this breaks cdi, since it cannot inject it anymore. At least AFAIK.
So, is there a way out of this? maybe using a secret solder feature?
_______________________________________________
seam-dev mailing list
https://lists.jboss.org/mailman/listinfo/seam-dev
_______________________________________________
seam-dev mailing list
https://lists.jboss.org/mailman/listinfo/seam-dev
--
Jason Porter
http://lightguard-jp.blogspot.com
http://twitter.com/lightguardjp
Software Engineer
Open Source Advocate
Author of Seam Catch - Next Generation Java Exception Handling
PGP key id: 926CCFF5
PGP key available at: keyserver.net, pgp.mit.edu
Loading...