Java class as condition in generic method - java

I have a Service which is responsible to gather some information through Providers. Depending on the information required, a certain Provider has to be used. For now the Provider is chosen upon a given Class. This example is simplified, but it should give a reasonable understanding of my setup
abstract class AbstractProvider {
private String provider = "MyProvider";
public String doSomethingAwsome() {
return provider;
}
}
class ProviderA extends AbstractProvider {
#Override
public String doSomethingAwsome() {
return super.doSomethingAwsome() + "_A";
}
}
class ProviderB extends AbstractProvider {
#Override
public String doSomethingAwsome() {
return super.doSomethingAwsome() + "_B";
}
}
class MyService {
private ProviderA providerA;
private ProviderB providerB;
MyService() {
providerA = new ProviderA();
providerB = new ProviderB();
}
public <T extends AbstractProvider> String doSomethingWithProvider(Class<T> providerClass) {
if (providerClass.equals(ProviderA.class)) {
return providerA.doSomethingAwsome();
} else if (providerClass.equals(ProviderB.class)) {
return providerB.doSomethingAwsome();
}
throw new IllegalArgumentException("No Provider found for Class: " + providerClass);
}
}
class Main {
public static void main(String[] args) {
MyService myService = new MyService();
String fromProviderA = myService.doSomethingWithProvider(ProviderA.class);
String fromProviderB = myService.doSomethingWithProvider(ProviderB.class);
System.out.printf("Provider A: %s, Provider B: %s", fromProviderA, fromProviderB);
}
}
Now I'm not happy with the solution in MyService.doSomethingWithProvider(). How would you implement this?
Is there a generic way of choosing the Provider? I dont like to use if-else clauses here.
Edit
Based on some suggestions, using a map seems better
class MyService {
private Map<Class<? extends AbstractProvider>, AbstractProvider> providers = new HashMap<>();
MyService() {
providers.put(ProviderA.class, new ProviderA());
providers.put(ProviderB.class, new ProviderB());
}
public <T extends AbstractProvider> String doSomethingWithProvider(Class<T> providerClass) {
if (providers.containsKey(providerClass)) {
return providers.get(providerClass).doSomethingAwsome();
}
new IllegalArgumentException("No Provider found for Class: " + providerClass)
}
}

Turing85 suggested to have a look at the Chain of Responsibility design pattern. Honestly I had to dig a little deeper for this one. The idea is quite easy to understand but getting my head around the implementation took me a little further.
So thanks for your input, I'm happy with this
abstract class AbstractProvider {
private String provider = "MyProvider";
public AbstractProvider nextProcessor;
public AbstractProvider(AbstractProvider nextProcessor) {
this.nextProcessor = nextProcessor;
}
public String doSomethingAwsome() {
return provider;
}
public abstract <T extends AbstractProvider> String doSomethingAwsome(Class<T> provider) throws IllegalArgumentException;
}
class ProviderA extends AbstractProvider {
public ProviderA (AbstractProvider nextProvider) {
super(nextProvider);
}
#Override
public String doSomethingAwsome() {
return super.doSomethingAwsome() + "_A";
}
#Override
public <T extends AbstractProvider> String doSomethingAwsome(Class<T> provider) throws IllegalArgumentException {
if (provider.equals(this.getClass())) {
return this.doSomethingAwsome();
} else if (nextProcessor != null) {
return nextProcessor.doSomethingAwsome(provider);
}
throw new IllegalArgumentException("No provider found for class: " + provider);
}
}
class ProviderB extends AbstractProvider {
public ProviderB (AbstractProvider nextProvider) {
super(nextProvider);
}
#Override
public String doSomethingAwsome() {
return super.doSomethingAwsome() + "_B";
}
#Override
public <T extends AbstractProvider> String doSomethingAwsome(Class<T> provider) throws IllegalArgumentException {
if (provider.equals(this.getClass())) {
return this.doSomethingAwsome();
} else if (nextProcessor != null) {
return nextProcessor.doSomethingAwsome(provider);
}
throw new IllegalArgumentException("No provider found for class: " + provider);
}
}
class MyService {
private AbstractProvider providerChain;
MyService() {
providerChain = new ProviderA(new ProviderB(null));
}
public <T extends AbstractProvider> String doSomethingWithProvider(Class<T> providerClass) {
return providerChain.doSomethingAwsome(providerClass);
}
}
I'm pretty sure you can do several more improvements here. Don't hesitate to give me your input

Related

Java generics api architecture

I'm implementing a strategy pattern for exceptions handling
public class GlobalExceptionHandler {
private interface Strategy<T extends Exception> {
ErrorResponse extract(T e);
}
private static class ResponseStatusStrategy implements Strategy<ResponseStatusException> {
#Override
public ErrorResponse extract(ResponseStatusException e) {
return ErrorResponse.builder()
.status(e.getStatus())
.message(e.getReason())
.description(e.getReason())
.build();
}
}
private static class IllegalStateStrategy implements Strategy<IllegalStateException> {
#Override
public ErrorResponse extract(IllegalStateException e) {
return ErrorResponse.builder()
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.message(e.getMessage())
.description("")
.build();
}
}
....
I call this API like this:
Exception ex = ....; // function param
if (ex instanceof ResponseStatusException) {
errorResponse = new ResponseStatusStrategy().extract((ResponseStatusException) ex);
} else if (ex instanceof IllegalStateException) {
errorResponse = new IllegalStateStrategy().extract((IllegalStateException) ex);
} else {
errorResponse = new EmptyStrategy().extract(ex);
}
Is there a more efficient and beautiful way to implement this? Idea gets me hint that I even didn't use interface method: "method extract(T e) is never used".
It would be great to have API like this:
Strategy<???> strategy;
if (ex instanceof ResponseStatusException) {
strategy = new ResponseStatusStrategy();
} else if (ex instanceof IllegalStateException) {
strategy = new IllegalStateStrategy();
} else {
strategy = new EmptyStrategy();
}
errorResponse = strategy.extract(ex);
You are trying to solve an object creational problem. You want a particular Strategy class object based on the StatusException class. Create a new class with a factory pattern to return you the correct object. Here is some dummy code inspired from your code.
private interface Factory {
Strategy buildStrategy(Exception e);
}
private static class FactoryImpl implements Factory {
public Strategy buildStrategy(Exception e) {
if (e instanceof IOException) {
return new Strategy1();
} else {
return new EmptyStrategy();
}
}
}
private interface Strategy<T extends Exception> {
String extract();
}
private static class Strategy1 implements Strategy<IOException> {
#Override public String extract() {
return "Strategy1";
}
}
private static class EmptyStrategy implements Strategy<NamingException> {
#Override public String extract() {
return "EmptyStrategy";
}
}
public static void main(String[] args) {
var f = new FactoryImpl();
System.out.println(f.buildStrategy(new IOException()).extract());
System.out.println(f.buildStrategy(new NamingException()).extract());
}

How generify class with T and List<T>

I am trying to generify my class structure.
I will show my real structure to be more specific.
I am writing application with offline mode support, so I decided to implement my ETag cache mechanism in using Robospice and GreenDao ORM.
I need to cache only GET requests.
Firstly my requests should extend base request(not mine), in my case RetrofitSpiceRequest<T, V>
T is type of return data
V is service type, in my case I am using Retrofit.
The problem is that return type is not List of T types by default and I need to create subclass that extends array of T objects and that use it as return type.
Something like this
public class City {
....
....
....
public static class List extends ArrayList<City> {
.....
.....
}
}
And use City.List as return type.
But I have my DAO declared as following
public class CityDao extends AbstractDao<City, Long> {
}
In each request (GET) I need to have specific DAO as a member in order to cache data if it differs from the server data. Or load data from the local database if there is no connection.
The problem here is that request generified by T type which is mostly list, City.List in my case, of some objects, but my dao is generified by, for example E type which is City in my case.
I want to create method like this
public AbastractDao<T,Long> getRequestDao() {
}
But as far as my Request returns City.List, I have no idea how to generify this class, I feel that it is possible, but now no ideas.
In case of non generic dao method, I have to duplicate code like this
#Override
public void insertReceivedData(City.List received) {
mCityDao.insertOrReplaceInTx(received);
}
#Override
public City.List getCachedData() {
if (mFilterMap != null && mFilterMap.size() > 0) {
return (City.List) mCityDao.loadAll();
} else {
WhereCondition[] whereConditions = QueryUtils.convertPropertyMapToConditionalArray(mFilterMap);
return (City.List) mCityDao.queryBuilder().where(whereConditions[0], Arrays.copyOfRange(whereConditions, 1, whereConditions.length)).list();
}
}
In each request
Please share your ideas.
Thanks.
I end up with following solution. It is not as good as I wanted, but it works and better than duplicating code.
My base request class.
public abstract class BaseGetRequest<L extends List<T>, T, V> extends RetrofitSpiceRequest<L, V> implements FilterableRequest {
// Context
protected Context mContext;
// Filter used in request and in queries
protected Map<Property, String> mFilterMap;
// Session provided Singletone
protected DaoSessionProvider mSessionProvider;
public BaseGetRequest(Class<L> clazz, Class<V> retrofitedInterfaceClass, Context context, Map<Property, String> filterMap) {
super(clazz, retrofitedInterfaceClass);
mContext = context;
mFilterMap = filterMap;
mSessionProvider = ((DaoSessionProvider) mContext.getApplicationContext());
// TODO determine required retry count
setRetryPolicy(new RetryPolicy() {
#Override
public int getRetryCount() {
return 0;
}
#Override
public void retry(SpiceException e) {
}
#Override
public long getDelayBeforeRetry() {
return 0;
}
});
}
protected WhereCondition[] getWhereConditions() {
return QueryUtils.convertPropertyMapToConditionalArray(mFilterMap);
}
public BaseGetRequestV2(Class<L> clazz, Class<V> retrofitedInterfaceClass, Context context) {
this(clazz, retrofitedInterfaceClass, context, null);
}
public abstract AbstractDao<T, Long> getDao();
public abstract L createDataList(List<T> list);
public L getCachedData() {
if (mFilterMap != null && mFilterMap.size() > 0) {
WhereCondition[] whereConditions = getWhereConditions();
return createDataList(getDao().queryBuilder().where(whereConditions[0], Arrays.copyOfRange(whereConditions, 1, whereConditions.length)).list());
} else {
return createDataList(getDao().loadAll());
}
}
public abstract L getData();
#Override
public Map<Property, String> getFilterMap() {
return mFilterMap;
}
public Map<String, String> getStringMap() {
return QueryUtils.convertPropertyMapToString(mFilterMap);
}
#Override
public L loadDataFromNetwork() throws Exception {
L receivedData = null;
try {
receivedData = getData();
WhereCondition[] conditions = getWhereConditions();
getDao().queryBuilder().where(conditions[0],Arrays.copyOfRange(conditions, 1, conditions.length)).buildDelete().executeDeleteWithoutDetachingEntities();
getDao().insertOrReplaceInTx(receivedData);
} catch (Exception ex) {
receivedData = getCachedData();
}
return receivedData;
}
}
And I can extend this class like so:
public class NewsRequest extends BaseGetRequest<NewsArticle.List, NewsArticle, API> {
public static final String TARGET_URL = "/news";
NewsArticleDao mNewsArticleDao;
public NewsRequest(Context context) {
this(context, null);
}
public NewsRequest(Context context, Map<Property, String> filterMap) {
super(NewsArticle.List.class, API.class, context, filterMap);
mNewsArticleDao = mSessionProvider.getDaoSession().getNewsArticleDao();
}
#Override
public AbstractDao<NewsArticle, Long> getDao() {
return mNewsArticleDao;
}
#Override
public NewsArticle.List createDataList(List<NewsArticle> list) {
return new NewsArticle.List(list);
}
#Override
public NewsArticle.List getData() {
return getService().getNews(getStringMap());
}
}

Java generics software engineering design

I have a class RabbitQueue which basically acts like a queue and implements my Pollable interface.
I also have a class SaveToDatabaseStrategy which implements my DataProcessingStrategy interface. This is designed following the strategy-pattern.
Now, my class InputHandler which implements my interface InputListener, contains an instance of the Pollable interface and one of the DataProcessingStrategy interface.
However, I don't want to set the Generic type (String) when I declare these two fields, since the Generic type depends on the implementation of this interface which is given later on.
How would you design this?
public interface Pollable<T> {
T poll();
}
public class RabbitQueue implements Pollable<String> {
// code..
}
public interface DataProcessingStrategy<T> {
void processData(T t);
}
public class SaveToDatabaseStrategy<T> implements DataProcessingStrategy<T> {
private Repository<T, ?> repo;
public SaveToDatabaseStrategy(Repository<T, ?> repo) {
this.repo = repo;
}
#Override
public void processData(T data) {
repo.create(data);
System.out.printf("Received data of type %s: %s\n", data.getClass().getSimpleName(), data);
}
}
public interface InputListener<T> {
void inputReceived();
void inputReceived(T t);
}
public class InputHandler implements InputListener<String> {
private Pollable<String> queue;
private DataProcessingStrategy<String> strategy;
public InputHandler(String host, String queueName) throws IOException, TimeoutException {
queue = new RabbitQueue(host, queueName, this);
}
public void setStrategy(DataProcessingStrategy strategy) {
this.strategy = strategy;
}
#Override
public void inputReceived() {
System.out.println("Input received!");
strategy.processData(queue.poll());
}
#Override
public void inputReceived(String s) {
System.out.println("Input received: " + s + "!");
System.out.println("> " + queue.poll());
}
}
You could add a type parameter to the InputHandler class.
public class InputHandler<T> implements InputListener<T> {
private Pollable<T> queue;
private DataProcessingStrategy<T> strategy;
public InputHandler(String host, String queueName) throws IOException, TimeoutException {
queue = new RabbitQueue(host, queueName, this);
}
public void setStrategy(DataProcessingStrategy strategy) {
this.strategy = strategy;
}
#Override
public void inputReceived() {
System.out.println("Input received!");
strategy.processData(queue.poll());
}
#Override
public void inputReceived(String s) {
System.out.println("Input received: " + s + "!");
System.out.println("> " + queue.poll().toString());
}
}
Then create a new object like
new InputHandler<String>(host, queueName)

How to design a type safe message API in Java?

I have a Java client which wants to communicate with a device through messages over serial communication. The client should be able to use a clean API, abstracting the ugly details of the serial communication. The client can send many types of messages through that API and gets responses. I'm searching for advice which way is best to implement this API.
For simplicity, say we have only two message types: HelloMessage which triggers a HelloResponse and InitMessage which triggers an InitResponse (in reality, there are many more)
Designing the API (that is, the Java abstraction of the device) I could have:
One method per message type:
public class DeviceAPI {
public HelloResponse sendHello(HelloMessage){...}
public InitResponse sendInit(InitMessage){...}
... and many more message types ....
This is nicely type safe. (It could also be many times the same send() method, overloaded, but that's about the same). But it is very explicit, and not very flexible - we cannot add messages without modification of the API.
I could also have a single send method, which takes all message types:
class HelloMessage implements Message
class HelloResponse implements Response
...
public class DeviceAPI {
public Response send(Message msg){
if(msg instanceof HelloMessage){
// do the sending, get the response
return theHelloResponse
} else if(msg instanceof ...
This simplifies the API (only one method) and allows for additional Message types to be added later without changing the API. At the same time, it requires the Client to check the Response type and cast it to the right type.
Client code:
DeviceAPI api = new DeviceAPI();
HelloMessage msg = new HelloMessage();
Response rsp = api.send(msg);
if(rsp instanceOf HelloResponse){
HelloResponse hrsp = (HelloResponse)rsp;
... do stuff ...
This is ugly in my opinion.
What do you recommend? Are there other approaches which give cleaner results?
References welcome! How did others solve this?
Here is a way to do it in type-safe (and extensible) way using generics:
public interface MessageType {
public static final class HELLO implements MessageType {};
}
public interface Message<T extends MessageType> {
Class<T> getTypeClass();
}
public interface Response<T extends MessageType> {
}
public class HelloMessage implements Message<MessageType.HELLO> {
private final String name;
public HelloMessage(final String name) {
this.name = name;
}
#Override
public Class<MessageType.HELLO> getTypeClass() {
return MessageType.HELLO.class;
}
public String getName() {
return name;
}
}
public class HelloResponse implements Response<MessageType.HELLO> {
private final String name;
public HelloResponse(final String name) {
this.name = name;
}
public String getGreeting() {
return "hello " + name;
}
}
public interface MessageHandler<T extends MessageType, M extends Message<T>, R extends Response<T>> {
R handle(M message);
}
public class HelloMessageHandler
implements MessageHandler<MessageType.HELLO, HelloMessage, HelloResponse> {
#Override
public HelloResponse handle(final HelloMessage message) {
return new HelloResponse(message.getName());
}
}
import java.util.HashMap;
import java.util.Map;
public class Device {
#SuppressWarnings("rawtypes")
private final Map<Class<? extends MessageType>, MessageHandler> handlers =
new HashMap<Class<? extends MessageType>, MessageHandler>();
public <T extends MessageType, M extends Message<T>, R extends Response<T>>
void registerHandler(
final Class<T> messageTypeCls, final MessageHandler<T, M, R> handler) {
handlers.put(messageTypeCls, handler);
}
#SuppressWarnings("unchecked")
private <T extends MessageType, M extends Message<T>, R extends Response<T>>
MessageHandler<T, M, R> getHandler(final Class<T> messageTypeCls) {
return handlers.get(messageTypeCls);
}
public <T extends MessageType, M extends Message<T>, R extends Response<T>>
R send(final M message) {
MessageHandler<T, M, R> handler = getHandler(message.getTypeClass());
R resposnse = handler.handle(message);
return resposnse;
}
}
public class Main {
public static void main(final String[] args) {
Device device = new Device();
HelloMessageHandler helloMessageHandler = new HelloMessageHandler();
device.registerHandler(MessageType.HELLO.class, helloMessageHandler);
HelloMessage helloMessage = new HelloMessage("abhinav");
HelloResponse helloResponse = device.send(helloMessage);
System.out.println(helloResponse.getGreeting());
}
}
To add support for a new message type, implement MessageType interface to create a new message type, implement Message, Response and MessageHandler interfaces for the new MessageType class and register the handler for the new message type by calling Device.registerHandler.
I've got a fully working example now of what you want:
To define the types of messages:
public interface MessageType {
public static class INIT implements MessageType { }
public static class HELLO implements MessageType { }
}
Base Message and Response classes:
public class Message<T extends MessageType> {
}
public class Response<T extends MessageType> {
}
Create custom init messages and responses:
public class InitMessage extends Message<MessageType.INIT> {
public InitMessage() {
super();
}
public String getInit() {
return "init";
}
}
public class InitResponse extends Response<MessageType.INIT> {
public InitResponse() {
super();
}
public String getInit() {
return "init";
}
}
Create custom hello messages and responses:
public class HelloMessage extends Message<MessageType.HELLO> {
public HelloMessage() {
super();
}
public String getHello() {
return "hello";
}
}
public class HelloResponse extends Response<MessageType.HELLO> {
public HelloResponse() {
super();
}
public String getHello() {
return "hello";
}
}
The DeviceAPI:
public class DeviceAPI {
public <T extends MessageType, R extends Response<T>, M extends Message<T>> R send(M message) {
if (message instanceof InitMessage) {
InitMessage initMessage = (InitMessage)message;
System.out.println("api: " + initMessage.getInit());
return (R)(new InitResponse());
}
else if (message instanceof HelloMessage) {
HelloMessage helloMessage = (HelloMessage)message;
System.out.println("api: " + helloMessage.getHello());
return (R)(new HelloResponse());
}
else {
throw new IllegalArgumentException();
}
}
}
Note that it does require an instanceof-tree, but you need that to handle what kind of message it is.
And a working example:
public static void main(String[] args) {
DeviceAPI api = new DeviceAPI();
InitMessage initMsg = new InitMessage();
InitResponse initResponse = api.send(initMsg);
System.out.println("client: " + initResponse.getInit());
HelloMessage helloMsg = new HelloMessage();
HelloResponse helloResponse = api.send(helloMsg);
System.out.println("client: " + helloResponse.getHello());
}
Output:
api: init
client: init
api: hello
client: hello
UPDATE: Added example on how to get input from the messages the client wants to send.
You could have a system of message handlers, and your DeviceAPI could choose which handler is suitable for the incoming message; and delegate it to the appropriate message handler:
class DeviceAPI {
private List<Handler> msgHandlers = new ArrayList<Handler>();
public DeviceAPI(){
msgHandlers.add(new HelloHandler());
//Your other message handlers can be added
}
public Response send(Message msg) throws Exception{
for (Handler handler : msgHandlers) {
if (handler.canHandle(msg)){
return handler.handle(msg);
}
}
throw new Exception("No message handler defined for " + msg);
}
}
The HelloHandler would look like:
interface Handler<T extends Message, U extends Response> {
boolean canHandle(Message message);
U handle(T message);
}
class HelloHandler implements Handler<HelloMessage, HelloResponse> {
#Override
public boolean canHandle(Message message) {
return message instanceof HelloMessage;
}
#Override
public HelloResponse handle(HelloMessage message) {
//Process your message
return null;
}
}
Ditto for your other messages. I'm sure you could make it more elegant, but the idea still remains the same - donot have one monster method with ifs; instead use polymorphism.
I don't think this is ugly at all:
if(rsp instanceOf HelloResponse){
HelloResponse hrsp = (HelloResponse)rsp;
...
else if ...
as long as you don't have like 100 different responses. You can encapsulate many kind of responses in one, depending on the data they have. For example:
class GenericResponse{
private String message;
private int responseType;
...
}
I have developed some multiplayer games and this is a good way to do it.
In case you have too many different types of messages, you just can use generic java types, like the example of skiwi above.
hope it helps

Java factory pattern - load classes dynamically

I have a lot of classes UNO,HAV,MAS,KOS
I want to create a factory pattern.
validator.load("UNO").validate();
I need dynamically load classes into validator class and return an instance.
(dynamically set name of the class and return an instance)
My problem is: how can I return the instance of a class, if I have incompatible types?
I don't know what to write in return type of method.
The main problem in the Validator CLASS.
public SegmentAbstract load(String str) {
AND
return SegmentAbsClass.forName(identify);
Main class
try{
validator.load("UNO").validate();
}catch(Exception e){
System.out.print("No class ");
}
Abstract Class (SegmentAbstract)
public abstract class SegmentAbstract {
public abstract Boolean validate();
}
Class UNO
public class UNA extends SegmentAbstract{
public Boolean validate() {
System.out.print("UNO!!");
return true;
}
}
Class Validator
public class Validator {
public SegmentAbstract load(String str) {
String identify = str.substring(0, 3);
try {
return SegmentAbsClass.forName(identify);
}
catch(Exception e) {
return this;
}
}
}
Try this :
public interface Validator {
boolean validate(Object obj);
}
public final class ValidatorFactory {
private ValidatorFactory(){}
public static Validator load(String type){
try {
Class<?> clazz = Class.forName(type);
if (Arrays.asList(clazz.getInterfaces()).contains(Validator.class)){
return (Validator) clazz.newInstance();
}
throw new IllegalArgumentException("Provided class doesn't implement Validator interface");
} catch (Exception e) {
throw new IllegalArgumentException("Wrong class provided", e);
}
}
}
Maybe this will help???
I will do something like that:
// ISegment.java
public interface ISegment {
Boolean validate();
}
// Uno.java
public class Uno implements ISegment {
public Boolean validate() {
System.out.print("UNO!!");
return true;
}
}
// SegmentFactory.java
public final class SegmentFactory {
public static enum Supported {
UNO("uno", Uno.class), /* ... */, HAV("hav", Hav.class);
private final Class<?> clazz;
private final String name;
private Supported(final String name, final Class<?> clazz) {
this.name = name;
this.clazz = clazz;
}
public Class<?> getClazz() {
return clazz;
}
public static Supported for(final String name) {
for (final Supported s : values()) {
if (s.name.equals(name) {
return s;
}
}
return null; // a default one
}
}
public static ISegment create(final Supported supp) {
if (supp == null) {
return null;
}
return supp.getClazz.newInstance();
}
private SegmentFactory() {
// avoid instantiation
}
}
usage:
final ISegment sa = SegmentFactory.create(SegmentFactory.Supported.for("uno"));
sa.validate();
Not tested!!
Take a look here. Briefly, the idea is to create a map in your factory class (Map<String,String>, key is identifier, value is fully qualified class name), and add supported classes during initialization. Then you use reflection to instantiate an object in your factory method. Also, you can avoid reflection by using Map<String, SegmentAbstract> instead of Map<String,String> and adding public abstract getNewSegment() to your SegmentAbstract class.

Categories