Consider the following scenario:
public abstract class A {}
public class B extends A {}
public interface Provider<T extends A> {
List<String> list(T param);
}
public class ProviderB implements Provider<B> {
#Override
public List<String> list(B param) {
return Collections.singletonList("ProviderB");
}
}
public class Factory {
public static Provider get(int x) {
if (x == 1)
return new ProviderB();
throw new RuntimeException("Not supported");
}
}
public class Main {
public static void main(String[] args) {
Provider provider = Factory.get(1);
A a = new B();
List<String> result = provider.list(a);
}
}
In Main at List<String> result = provider.list(a); , I'm getting:
Unchecked call to list(T) ..
Unchecked assignment java.util.List .. Reason 'provider' has raw type.
I do know some basic stuff about type erasure in generics. How would you solve the warnings ?
EDIT:
Actually main will look like this:
public static void main(Map<Integer, ? extends A> types) {
for (Map.Entry<Integer, ? extends A> entryType : types.entrySet()) {
Provider provider = Factory.get(entryType.getKey());
List<String> result = provider.list(entryType.getValue());
}
}
I've a situation similar to this.
What if I still want to call constructors conditionally? (Though they said creating separate classes is suggestible)
Requirement structure:
Super class:
public class Super
{
public Super(DTO1 dto1Object){
this.dto1Object = dto1Object;
}
public Super(DTO2 dto2Object)){
this.dto2Object = dto2Object;
}
}
Derived class:
public class Derived extends Super
{
public Derived(Object obj)
{
//some_condition to check if passed object obj is dto1Object
//do something with dto1Object
//some_condition to check if passed object is dto2Object
//do something with dto2Object
}
}
How should I implement it?
EDIT:
Implemented it in this way based on the suggestion below:
Super class:
public class Super
{
protected static DTO1 dto1Obj;
protected static DTO2 dto2Obj;
public Super(DTO1 dto1Object){
this.dto1Object = dto1Object;
}
public Super(DTO2 dto2Object)){
this.dto2Object = dto2Object;
}
}
Derived class:
public class Derived extends Super
{
public Derived(DTO1 dto1Object){ super(dto1Object); }
public Derived(DTO2 dto2Object){ super(dto2Object); }
public static Derived create(Object obj) {
if (obj.equals(dto1Obj) {
return new Derived((DTO1) obj);
}
if (obj.equals(dto2Obj) {
return new Derived((DTO2) obj);
}
// ...
private String Function(String str){
if(create(dto1Obj).equals(dto1Obj) {
//do something
}
else if(create(dto2Obj).equals(dto2Obj)){
//do something else
}
return str;
}
}
}
EDIT2:
As per suggestion below, is this the correct way to use instanceof?
if (create(dto1Obj) instanceof DTO1) {
//something
}
else if(create(dto2Obj) instanceof DTO2) {
//something else
}
Is shows the following error:
Incompatible conditional operand types Derived and DTO1
Incompatible conditional operand types Derived and DTO2
You can't in the constructor, because the super(...) has to be the first statement.
The only way I can think is to use a static factory method, and invoke class-specific overloads of the constructor:
public class Derived extends Super
{
private Derived(DTO1 dto1Object){ super(dto1Object); }
private Derived(DTO2 dto2Object){ super(dto2Object); }
public static Derived create(Object obj) {
//some_condition to check if passed object obj is dto1Object
//do something with dto1Object
if (someCondition) {
return new Derived((DTO1) obj);
}
//some_condition to check if passed object is dto2Object
//do something with dto2Object
if (someOtherCondition) {
return new Derived((DTO2) obj);
}
// ...?
}
}
I have a generic interface Handler
public interface Handler<T> {
void handle(T obj);
}
I can have n implementations of this interface. Let's say I have following 2 implementations for now. One which handles String objects and another handles Date
public class StringHandler implements Handler<String> {
#Override
public void handle(String str) {
System.out.println(str);
}
}
public class DateHandler implements Handler<Date> {
#Override
public void handle(Date date) {
System.out.println(date);
}
}
I want to write a factory which will return handler instances based on the class type. Something like this :
class HandlerFactory {
public <T> Handler<T> getHandler(Class<T> clazz) {
if (clazz == String.class) return new StringHandler();
if (clazz == Date.class) return new DateHandler();
}
}
I get following error in this factory :
Type mismatch: cannot convert from StringHandler to Handler<T>
How to fix this?
SIMPLE SOLUTION
You could save your mappings Class<T> -> Handler<T> in a Map. Something like:
Map<Class<T>, Handler<T>> registry = new HashMap<>();
public void registerHandler(Class<T> dataType, Class<? extends Handler> handlerType) {
registry.put(dataType, handlerType);
}
public <T> Handler<T> getHandler(Class<T> clazz) {
return registry.get(clazz).newInstance();
}
In some place, initialize handlers (could be in the factory itself):
factory.registerHandler(String.class, StringHandler.class);
factory.registerHandler(Date.class, DateHandler.class);
And in another place, you create and use them:
Handler<String> stringhandler = factory.getHandler(String.class);
Handler<Date> dateHandler = factory.getHandler(Date.class);
MORE COMPLEX SOLUTION
You can "scan" classes using reflection and, instead of register manually the mappings Class<T> -> Handler<T>, do it using reflection.
for (Class<? extends Handler> handlerType : getHandlerClasses()) {
Type[] implementedInterfaces = handlerType.getGenericInterfaces();
ParameterizedType eventHandlerInterface = (ParameterizedType) implementedInterfaces[0];
Type[] types = eventHandlerInterface.getActualTypeArguments();
Class dataType = (Class) types[0]; // <--String or Date, in your case
factory.registerHandler(dataType, handlerType);
}
Then, you create and use them like above:
Handler<String> stringhandler = factory.getHandler(String.class);
Handler<Date> dateHandler = factory.getHandler(Date.class);
To implement getHandlerClasses(), look at this to scan all classes in your jar. For each class, you have to check if it is a Handler:
if (Handler.class.isAssignableFrom(scanningClazz) //implements Handler
&& scanningClazz.getName() != Handler.class.getName()) //it is not Handler.class itself
{
//is a handler!
}
Hope it helps!
Your problem is that the compiler cannot make the leap to the fact thet the type of the result is correct.
To help the compiler you can make the factory delegate the construction. Although this looks strange and unwieldly it does manage to properly maintain type safety without sacrifices such as casting or using ? or raw types.
public interface Handler<T> {
void handle(T obj);
}
public static class StringHandler implements Handler<String> {
#Override
public void handle(String str) {
System.out.println(str);
}
}
public static class DateHandler implements Handler<Date> {
#Override
public void handle(Date date) {
System.out.println(date);
}
}
static class HandlerFactory {
enum ValidHandler {
String {
#Override
Handler<String> make() {
return new StringHandler();
}
},
Date {
#Override
Handler<Date> make() {
return new DateHandler();
}
};
abstract <T> Handler<T> make();
}
public <T> Handler<T> getHandler(Class<T> clazz) {
if (clazz == String.class) {
return ValidHandler.String.make();
}
if (clazz == Date.class) {
return ValidHandler.Date.make();
}
return null;
}
}
public void test() {
HandlerFactory factory = new HandlerFactory();
Handler<String> stringHandler = factory.getHandler(String.class);
Handler<Date> dateHandler = factory.getHandler(Date.class);
}
The whole point of using a generic type is to share the implementation. If the n implementation of your Handler interface are so different that they can't be shared, then I don't think there is any reason to use define that generic interface at the first place. You'd rather just have StringHandler and DateHandler as top level classes.
On the other hand, if the implementation can be shared, as is the case of your example, then the factory works naturally:
public class Main {
static public interface Handler<T> {
void handle(T obj);
}
static public class PrintHandler<T> implements Handler<T> {
#Override
public void handle(T obj) {
System.out.println(obj);
}
}
static class HandlerFactory {
public static <T> Handler<T> getHandler() {
return new PrintHandler<T>();
}
}
public static void main(String[] args) {
Handler<String> stringHandler = HandlerFactory.getHandler();
Handler<Date> dateHandler = HandlerFactory.getHandler();
stringHandler.handle("TEST");
dateHandler.handle(new Date());
}
}
You can use something like:
class HandlerFactory {
public <T> Handler<T> getHandler(Class<T> clazz) {
if (clazz.equals(String.class)) return (Handler<T>) new StringHandler();
if (clazz.equals(Date.class)) return (Handler<T>) new DateHandler();
return null;
}
}
T is generic and the compiler can't map that at compile time. Also it is safer to use .equals instead of ==.
Define an interface for creating an object, but let subclasses decide which class to instantiate.
Factory method lets a class defer instantiation to subclasses.
Define generic abstract class
public abstract class Factory<T> {
public abstract T instantiate(Supplier<? extends T> supplier);
}
And a generic supplier
public class SupplierFactory<T> extends Factory<T> {
#Override
public T instantiate(Supplier<? extends T> supplier) {
return supplier.get();
}
}
Then an implementation needs to have concrete classes to implement the base interface and a main class to show class defer instantiation . i.e
The base interface (desired interface of the requirement)
public interface BaseInterface {
void doAction();
}
The first concrete class
public class Alpha implements BaseInterface {
#Override
public void doAction() {
System.out.println("The Alpha executed");
}
}
And the second one
public class Beta implements BaseInterface {
#Override
public void doAction() {
System.out.println("The Beta executed");
}
}
The main
public class Main {
public static void main(String[] args) {
Factory<BaseInterface> secondFactory = new SupplierFactory<>();
secondFactory.instantiate(Beta::new).doAction();
secondFactory.instantiate(Alpha::new).doAction();
}
}
Basically you can do:
public Handler getHandler( Class clazz ){
if( clazz == String.class ) return new StringHandler();
if( clazz == Date.class ) return new DateHandler();
return null;
}
public static void main( String[] args ){
HandlerFactory handlerFactory = new HandlerFactory();
StringHandler handler = ( StringHandler )handlerFactory.getHandler( String.class );
handler.handle( "TEST" );
DateHandler handler2 = ( DateHandler )handlerFactory.getHandler( Date.class );
handler2.handle( new Date() );
}
Output:
TEST
Tue Dec 15 15:31:00 CET 2015
But instead writing two different methods to get handlers separately always is a better way.
I edited your code and allowed Eclipse to "fix" the errors and it came up with this.
public Handler<?> getHandler(Class<?> clazz) {
if (clazz == String.class)
return new StringHandler();
if (clazz == Date.class)
return new DateHandler();
return null;
}
Yout HandlerFactory don't know about T. Use your factory like below-
public class HandlerFactory {
public Handler<?> getHandler(Class<?> clazz) {
if (clazz == String.class) {
return new StringHandler();
}
if (clazz == Date.class) {
return new DateHandler();
}
return null;
}
}
I have an third-party RPC-API that provides an interface similar to that of java.sql.ResultSet (for reading values) and java.sql.PreparedStatement (for writing values). Assume it looks something like this:
public interface RemoteDeviceProxy {
public void setBoolean(Boolean value);
public void setInteger(Integer value);
// ...
public Boolean getBoolean();
public Integer getInteger();
// ...
}
I want to write a wrapper for this API that uses generics to create instances of specific types:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
public RemoteVariable(RemoteDeviceProxy wrappedDevice) {
this.wrappedDevice = wrappedDevice;
}
public T get() {
// should call wrappedDevice.getBoolean() if T is Boolean, etc.
// how to implement?
}
public void set(T newValue) {
// should call wrappedDevice.setBoolean(newValue) if T is Boolean, etc.
// implement using instanceof
}
}
How can I implement the getter in my generic wrapper? I have found this answer which explains a similar scenario in depth, but I am not able to transfer this to my problem. Specifically, when I write this:
public T get() {
Type[] actualTypeArguments = ((ParameterizedType) getClass())
.getActualTypeArguments();
}
I get a compiler error saying I cannot cast to ParameterizedType, and I do not understand why. Can anyone explain how to achieve this?
Here is one way:
public class <T> RemoteVariable {
private final RemoteDeviceProxy wrappedDevice;
private final Class<T> clazz;
public RemoteVariable(RemoteDeviceProxy wrappedDevice, Class<T> clazz) {
this.wrappedDevice = wrappedDevice;
this.clazz = clazz;
}
public T get() {
if(clazz == Boolean.class){return clazz.cast(wrappedDevice.getBoolean());}
else if(clazz == Integer.class){return clazz.cast(wrappedDevice.getInteger());}
// ...
}
// ...
}
I thought over this quite a while and finally came up with a different approach:
First I added a getter to you RemoteVariable class:
protected RemoteDeviceProxy getWrappedProxy() {
return wrappedProxy;
}
Second I created a builder interface that will be used by a factory later:
public interface RemoteVariableBuilder {
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy);
}
Then I created non generic sub classes for Boolean...
public class RemoteBooleanVariable extends RemoteVariable<Boolean> implements RemoteVariableBuilder {
public RemoteBooleanVariable(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteBooleanVariable(wrappedProxy);
}
#Override
public Boolean get() {
return getWrappedProxy().getBoolean();
}
#Override
public void set(Boolean value) {
getWrappedProxy().setBoolean(value);
}
}
... and Integer ...
public class RemoteIntegerBuilder extends RemoteVariable<Integer> implements RemoteVariableBuilder {
public RemoteIntegerBuilder(RemoteDeviceProxy wrappedProxy) {
super(wrappedProxy);
}
#SuppressWarnings("unchecked")
#Override
public <T> RemoteVariable<T> buildNewVariable(RemoteDeviceProxy wrappedProxy) {
return (RemoteVariable<T>) new RemoteIntegerBuilder(wrappedProxy);
}
#Override
public Integer get() {
return getWrappedProxy().getInteger();
}
#Override
public void set(Integer value) {
getWrappedProxy().setInteger(value);
}
}
actually eclipse created most of the code once it knew base class and interface.
The final step was to create a factory
public class RemoteVariableFactory {
private static final Map<String, RemoteVariableBuilder> BUILDERS = new HashMap<>();
static {
BUILDERS.put(Boolean.class.getName(), new RemoteBooleanVariable(null));
BUILDERS.put(Integer.class.getName(), new RemoteIntegerBuilder(null));
// add more builders here
}
public static <T> RemoteVariable<T> getRemoteVariable(RemoteDeviceProxy wrappedProxy, Class<T> typeClass) {
RemoteVariableBuilder remoteVariableBuilder = BUILDERS.get(typeClass.getName());
if (remoteVariableBuilder == null) {
return null; // or throw an exception whichever is better in your case
}
return remoteVariableBuilder.buildNewVariable(wrappedProxy);
}
}
Now we are ready to create new RemoteVariables...
RemoteVariable<Boolean> var1 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Boolean.class);
RemoteVariable<Integer> var2 = RemoteVariableFactory.getRemoteVariable(new RemoteDevice(), Integer.class);
To conclude this let's do a quick comparison to the answer of Eng.Fouad:
Disadvantage:
you need to create a new class for every datatype you provide
Advantage:
you only have to add one line to the static block of the factory and not two new if blocks to the getter and setter in RemoteVariable
get and set do not have to work through the if-else-blocks every time
If I have this class:
class Foo<T> implements SomeInterface
{
final private List<T> list = new ArrayList<T>();
final private Class<? extends T> runtimeClass;
public Foo(Class<? extends T> cl) { this.runtimeClass = cl; }
// method override from SomeInterface
#Override public boolean addChild(Object o)
{
// Only add to list if the object is an acceptible type.
if (this.runtimeClass.isInstance(o))
{
list.add( /* ??? how do we cast o to type T??? */ );
}
}
public List<T> getList()
{
return this.list;
} // yes, I know, this isn't safe publishing....
}
how would I perform a runtime cast from Object to type T?
Use this:
list.add(this.runtimeClass.cast(o))
See Class.cast() for details
// method override from SomeInterface
#Override public boolean addChild(Object o)
{
// Only add to list if the object is an acceptible type.
if (this.runtimeClass.isInstance(o))
{
list.add((T)o);
}
}