Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > comp.lang.java.programmer > #36203 > unrolled thread
| Started by | Philipp Kraus <philipp.kraus.flashpixx@gmail.com> |
|---|---|
| First post | 2017-01-21 08:19 -0800 |
| Last post | 2017-01-22 09:14 +0100 |
| Articles | 8 — 4 participants |
Back to article view | Back to comp.lang.java.programmer
class parameter with generic type on a factory Philipp Kraus <philipp.kraus.flashpixx@gmail.com> - 2017-01-21 08:19 -0800
Re: class parameter with generic type on a factory Andreas Leitgeb <avl@logic.at> - 2017-01-21 19:33 +0000
Re: class parameter with generic type on a factory Philipp Kraus <philipp.kraus.flashpixx@gmail.com> - 2017-01-21 11:51 -0800
Re: class parameter with generic type on a factory Andreas Leitgeb <avl@logic.at> - 2017-01-21 20:11 +0000
Re: class parameter with generic type on a factory Arne Vajhøj <arne@vajhoej.dk> - 2017-01-21 23:04 -0500
Re: class parameter with generic type on a factory Andreas Leitgeb <avl@logic.at> - 2017-01-22 11:02 +0000
Re: class parameter with generic type on a factory Arne Vajhøj <arne@vajhoej.dk> - 2017-01-22 14:00 -0500
Re: class parameter with generic type on a factory Marcel Mueller <news.5.maazl@spamgourmet.org> - 2017-01-22 09:14 +0100
| From | Philipp Kraus <philipp.kraus.flashpixx@gmail.com> |
|---|---|
| Date | 2017-01-21 08:19 -0800 |
| Subject | class parameter with generic type on a factory |
| Message-ID | <39e83ab1-6a6a-4211-8f3b-0237d56d4202@googlegroups.com> |
Hello,
I have git an interface
interface MyInterface<T> {}
based on this Interface I have a class
public MyClass<T> implements MyInterface<T> {}
and a factory class which generates MyInterface<T> objects with a Class parameter at the constructor
class MyFactory<T>
{
private final Constructor<? extends MyInterface<T>> m_ctor;
public MyFactor( final Class<? extends MyInterface<T>> p_class )
{
m_ctor = p_class.getConstructor();
}
}
If I try to create an object of the factory with
new MyFactor<String>( MyClass.class );
I get an error that MyClass.class is from the wrong type, the parameter should be a class from the type MyInterface<T>.
So I try to modify the ctor of the factory:
public <G extends MyInterface<T> MyFactor( final Class<G> p_class )
{
m_ctor = p_class.getConstructor();
}
but I get the error on compiling:
reason: cannot infer type-variable(s) T,G (actual and formal argument lists differ in length)
I have tried it also with an abstract class, which will be used instead of the class MyInterface.
So my goal is to create flexible factory, which get through the ctor the class which will be constructed, but I will restrict the constructed objects of an interface
The problem seems to be with the generic parameter.
How can I solve this problem?
Thanks
Phil
[toc] | [next] | [standalone]
| From | Andreas Leitgeb <avl@logic.at> |
|---|---|
| Date | 2017-01-21 19:33 +0000 |
| Message-ID | <slrno87drj.pvm.avl@logic.at> |
| In reply to | #36203 |
Philipp Kraus <philipp.kraus.flashpixx@gmail.com> wrote:
> I have got an interface
> interface MyInterface<T> {}
> based on this Interface I have a class
> public MyClass<T> implements MyInterface<T> {}
> and a factory class which generates MyInterface<T> objects with a Class parameter at the constructor
> [...]
> If I try to create an object of the factory with
> new MyFactor<String>( MyClass.class );
It is important to understand that in Java generics are primarily a
compile-time thing. If the compiler can see that all types fit, then it
can guarantee that no ClassCastException will possibly surprise you at
runtime, (except where you do an explicit cast).
Now, if you pass MyClass.class to the factory, there is no way for
the *compiler* to know that these instances will consistently have
the used factory's type param as their type param.
*You* on the other hand *can* tell for sure, that the instances you
create will only ever be used with the factory's type parameter, like
String.
This is the situation, where it is ok to "help" the compiler and tell
it that the instance you create (which originally is of type MyClass<?>,
and thus only implements MyInterface<?>) can safely be assumed to be
always e.g. a MyClass<String> (if String was the used factory's type
param).
You do this by using the annotation @SuppressWarnings("unchecked")
on the method that calls newInstance on the provided constructor and
casts(!) the MyClass<?> to MyClass<T> (where T here is the factory's
type param). It's then your responsibility that no ref to such an
instance will ever be cast to a different type parameter, but that's
not likely to happen in your factory method, anyway.
[toc] | [prev] | [next] | [standalone]
| From | Philipp Kraus <philipp.kraus.flashpixx@gmail.com> |
|---|---|
| Date | 2017-01-21 11:51 -0800 |
| Message-ID | <7049a3a0-7c09-41fa-97c0-82d54b06061e@googlegroups.com> |
| In reply to | #36204 |
Am Samstag, 21. Januar 2017 20:35:07 UTC+1 schrieb Andreas Leitgeb:
> Philipp Kraus <philipp.kraus.flashpixx@gmail.com> wrote:
> > I have got an interface
> > interface MyInterface<T> {}
> > based on this Interface I have a class
> > public MyClass<T> implements MyInterface<T> {}
> > and a factory class which generates MyInterface<T> objects with a Class parameter at the constructor
> > [...]
> > If I try to create an object of the factory with
> > new MyFactor<String>( MyClass.class );
>
> It is important to understand that in Java generics are primarily a
> compile-time thing. If the compiler can see that all types fit, then it
> can guarantee that no ClassCastException will possibly surprise you at
> runtime, (except where you do an explicit cast).
>
> Now, if you pass MyClass.class to the factory, there is no way for
> the *compiler* to know that these instances will consistently have
> the used factory's type param as their type param.
>
> *You* on the other hand *can* tell for sure, that the instances you
> create will only ever be used with the factory's type parameter, like
> String.
>
> This is the situation, where it is ok to "help" the compiler and tell
> it that the instance you create (which originally is of type MyClass<?>,
> and thus only implements MyInterface<?>) can safely be assumed to be
> always e.g. a MyClass<String> (if String was the used factory's type
> param).
>
> You do this by using the annotation @SuppressWarnings("unchecked")
> on the method that calls newInstance on the provided constructor and
> casts(!) the MyClass<?> to MyClass<T> (where T here is the factory's
> type param). It's then your responsibility that no ref to such an
> instance will ever be cast to a different type parameter, but that's
> not likely to happen in your factory method, anyway.
Thanks for your answer, I know that generic (or in C++ templates) are only exist on compile-time, but not on runtime. But the questian is, is there a possibility to pass the template argument to the class object. I'm working with Java 8.
For the compiler I need not a MyClass.class, but I need a MyClass<String>.class object, but if this is not possible can I do it without a type-cast?
Thanks
Phil
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@logic.at> |
|---|---|
| Date | 2017-01-21 20:11 +0000 |
| Message-ID | <slrno87g3s.pvm.avl@logic.at> |
| In reply to | #36206 |
Philipp Kraus <philipp.kraus.flashpixx@gmail.com> wrote:
> Am Samstag, 21. Januar 2017 20:35:07 UTC+1 schrieb Andreas Leitgeb:
>> Philipp Kraus <philipp.kraus.flashpixx@gmail.com> wrote:
>> > I have got an interface
>> > interface MyInterface<T> {}
>> > based on this Interface I have a class
>> > public MyClass<T> implements MyInterface<T> {}
>> > and a factory class which generates MyInterface<T> objects with a Class parameter at the constructor
>> > [...]
>> > If I try to create an object of the factory with
>> > new MyFactor<String>( MyClass.class );
>> It is important to understand that in Java generics are primarily a
>> compile-time thing. If the compiler can see that all types fit, then it
>> can guarantee that no ClassCastException will possibly surprise you at
>> runtime, (except where you do an explicit cast).
>>
>> Now, if you pass MyClass.class to the factory, there is no way for
>> the *compiler* to know that these instances will consistently have
>> the used factory's type param as their type param.
>>
>> *You* on the other hand *can* tell for sure, that the instances you
>> create will only ever be used with the factory's type parameter, like
>> String.
>>
>> This is the situation, where it is ok to "help" the compiler and tell
>> it that the instance you create (which originally is of type MyClass<?>,
>> and thus only implements MyInterface<?>) can safely be assumed to be
>> always e.g. a MyClass<String> (if String was the used factory's type
>> param).
>>
>> You do this by using the annotation @SuppressWarnings("unchecked")
>> on the method that calls newInstance on the provided constructor and
>> casts(!) the MyClass<?> to MyClass<T> (where T here is the factory's
>> type param). It's then your responsibility that no ref to such an
>> instance will ever be cast to a different type parameter, but that's
>> not likely to happen in your factory method, anyway.
>
> Thanks for your answer, I know that generic (or in C++ templates) are
> only exist on compile-time, but not on runtime.
You know partially wrong. It is true for Java, but C++ templates are
different. Unlike Java, C++ does know the type parameters at runtime:
it even creates a copy of the template code for each parameterization
(with some gory exceptions that I don't want to go deeper into, here).
> But the questian is, is there a possibility to pass the template
> argument to the class object. I'm working with Java 8.
Maybe my previous answer was "tl;dr", but it was meant to clarify: "no".
> For the compiler I need not a MyClass.class, but I need a
> MyClass<String>.class object, but if this is not possible
> can I do it without a type-cast?
No, you cannot specify MyClass<String>.class - Yes, you need to cast,
and yes, you can squelsh the generics-cast-warning, and you need not
even feel bad about it for this particular "class-factory" usecase.
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2017-01-21 23:04 -0500 |
| Message-ID | <o61avt$tmt$1@gioia.aioe.org> |
| In reply to | #36203 |
On 1/21/2017 11:19 AM, Philipp Kraus wrote:
> I have git an interface
>
> interface MyInterface<T> {}
>
> based on this Interface I have a class
>
> public MyClass<T> implements MyInterface<T> {}
>
> and a factory class which generates MyInterface<T> objects with a Class parameter at the constructor
>
> class MyFactory<T>
> {
> private final Constructor<? extends MyInterface<T>> m_ctor;
>
> public MyFactor( final Class<? extends MyInterface<T>> p_class )
> {
> m_ctor = p_class.getConstructor();
> }
>
> }
>
> If I try to create an object of the factory with
>
> new MyFactor<String>( MyClass.class );
>
> I get an error that MyClass.class is from the wrong type, the parameter should be a class from the type MyInterface<T>.
>
> So I try to modify the ctor of the factory:
>
> public <G extends MyInterface<T> MyFactor( final Class<G> p_class )
> {
> m_ctor = p_class.getConstructor();
> }
>
> but I get the error on compiling:
>
> reason: cannot infer type-variable(s) T,G (actual and formal argument lists differ in length)
>
> I have tried it also with an abstract class, which will be used instead of the class MyInterface.
>
> So my goal is to create flexible factory, which get through the ctor
> the class which will be constructed, but I will restrict the
> constructed objects of an interface
I am not sure that there is a good solution.
:-(
Some experimentation ended up with this:
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
public class GenFun {
public static interface MyInterface<T> {
public T giveMe();
}
public static class MyClass<T> implements MyInterface<T> {
public T giveMe() {
return null; // not easy to create a T but that is another problem
}
}
public static class MyFactory<T>
{
private final Constructor<? extends MyClass<T>> ctor;
public MyFactory(Class<? extends MyClass<T>> clz) throws
NoSuchMethodException, SecurityException
{
ctor = clz.getConstructor();
}
public MyInterface<T> create() throws InstantiationException,
IllegalAccessException, IllegalArgumentException,
InvocationTargetException {
return ctor.newInstance(new Object[0]);
}
}
public static void main(String[] args) throws NoSuchMethodException,
SecurityException, InstantiationException, IllegalAccessException,
IllegalArgumentException, InvocationTargetException {
@SuppressWarnings("unchecked")
MyFactory<String> mf = new MyFactory<String>((Class<? extends
MyClass<String>>) MyClass.class);
MyInterface<String> mi = mf.create();
String s = mi.giveMe();
System.out.println(s == null);
}
}
Arne
[toc] | [prev] | [next] | [standalone]
| From | Andreas Leitgeb <avl@logic.at> |
|---|---|
| Date | 2017-01-22 11:02 +0000 |
| Message-ID | <slrno8949c.pvm.avl@logic.at> |
| In reply to | #36208 |
Arne Vajhøj <arne@vajhoej.dk> wrote:
> Some experimentation ended up with this:
> public static interface MyInterface<T> ...
> public static class MyClass<T> implements MyInterface<T> ...
> public static class MyFactory<T> {
> public MyFactory(Class<? extends MyClass<T>> clz) ...
> }
Indeed, the factory method can specify a type-parameterized class for
its argument, which removes the "dirty" unchecked cast from inside the
factory, but there is no way to completely get rid of the unchcked cast.
> public static void main(String[] args) throws [...] {
> @SuppressWarnings("unchecked")
> MyFactory<String> mf = new MyFactory<String>(
> (Class<? extends MyClass<String>>)MyClass.class
> );
Actually, I think leaving the cast inside the factory makes for cleaner
code.
[toc] | [prev] | [next] | [standalone]
| From | Arne Vajhøj <arne@vajhoej.dk> |
|---|---|
| Date | 2017-01-22 14:00 -0500 |
| Message-ID | <o62vfh$1ae4$1@gioia.aioe.org> |
| In reply to | #36211 |
On 1/22/2017 6:02 AM, Andreas Leitgeb wrote:
> Arne Vajhøj <arne@vajhoej.dk> wrote:
>> Some experimentation ended up with this:
>> public static interface MyInterface<T> ...
>> public static class MyClass<T> implements MyInterface<T> ...
>> public static class MyFactory<T> {
>> public MyFactory(Class<? extends MyClass<T>> clz) ...
>> }
>
> Indeed, the factory method can specify a type-parameterized class for
> its argument, which removes the "dirty" unchecked cast from inside the
> factory, but there is no way to completely get rid of the unchcked cast.
>
>> public static void main(String[] args) throws [...] {
>> @SuppressWarnings("unchecked")
>> MyFactory<String> mf = new MyFactory<String>(
>> (Class<? extends MyClass<String>>)MyClass.class
>> );
>
> Actually, I think leaving the cast inside the factory makes for cleaner
> code.
It was the best that my limited creativity and the Java
compiler could agree on.
:-)
Arne
[toc] | [prev] | [next] | [standalone]
| From | Marcel Mueller <news.5.maazl@spamgourmet.org> |
|---|---|
| Date | 2017-01-22 09:14 +0100 |
| Message-ID | <o61plf$5m2$1@gwaiyur.mb-net.net> |
| In reply to | #36203 |
On 21.01.17 17.19, Philipp Kraus wrote:
> class MyFactory<T>
> {
> private final Constructor<? extends MyInterface<T>> m_ctor;
>
> public MyFactor( final Class<? extends MyInterface<T>> p_class )
> {
> m_ctor = p_class.getConstructor();
> }
>
> }
I had a slightly similar problem some time ago and ended up like that:
<T> T JNDILookup(Class<T> type, String name) throws Event
{ try
{ return type.cast(jndiContext.lookup(name));
} catch (NamingException e)
{ throw new Event(Events.EVF_JNDIObjectNotFound, name, type.getName(),
jndiUrl, ExceptionFormatter.toString(e));
} catch (ClassCastException e)
{ throw new Event(Events.EVF_JNDIObjectWrongType, name, type.getName(),
jndiUrl, ExceptionFormatter.toString(e));
}
}
Call:
JNDILookup(QueueConnectionFactory.class, connectionName)
But no further type checks on T there because the executing code must
not depend on the actual type in Java and AFAIK Java cannot deduce more
than one type argument from a single function argument, i.e. your class
name and the interface type.
> So my goal is to create flexible factory, which get through the ctor the class which will be constructed, but I will restrict the constructed objects of an interface
> The problem seems to be with the generic parameter.
>
> How can I solve this problem?
Well, choose another language without type erasure. :-(
This is e.g. straight forward in .NET, although it uses reflection
internally to create the instances in this case (slow).
Note also that this cyclic dependencies of a generic interface (or an
abstract super class) on the implementing class break inheritance.
class A implements MyInterface<A>
{...}
class B extends A
{...}
The MyInterface implementation is broken for B because if misses the
constraint MyInterface<B>.
This is probably related to the problem that Java has with Class<?
extends MyInterface<T>>.
Marcel
[toc] | [prev] | [standalone]
Back to top | Article view | comp.lang.java.programmer
csiph-web