How to write a enum that would take generics variable - java

I have a usecase to create a Singleton cache using enum. The key and value of the cache should be generic variable.
Enum in java do not directly take generic variables. Not perfectly sure if that can be done if implementing an interface. Although it works to an extent if we provide the datatype in place of generics variables. To explain this. The below code is fine without compilation error.
public enum MyCache implements Cache<String, String> {
INSTANCE;
#Override
public void putIntoMyCache(String dK, String dV) {
domainDataCache.put(dK, dV);
}
#Override
public Optional<String> getFromMyCache(String dK) {
return domainDataCache.get(dK);
}
private DomainDataCache<String, String> domainDataCache = new DomainDataCache();
}
public interface Cache<Key,Value> {
public void putIntoLgiCache(Key dK, Value dV);
public Optional<Value> getFromLgiCache(Key dK);
}
In the above code we implemented Cache interface using
Cache<String, String>
which works. But I need to have a
cache<Key,Value>
whose key and value needs to be generic variable,
I have no clue if this is possible in java!!
Thanks in advance Guys!!

Related

Extend a Java Enum with additional functions

I have an enum from a common Library (it cannot be changed) as a field from a Class.
I need to use that enum values as a switch-case in order to do something accordingly (for example save some data to a database).
This is for a Java 11 micro-service using Spring as a framework.
What I did before knowing the enum has to stay immutable, I avoided an ugly switch case with an overridden abstract function inside the enum like this:
public enum InvoiceStatus {
DRAFT {
#Override public void action(InputMessage inputMessage) {
invoiceFileService.draft(inputMessage);
}
},
VALID {
#Override public void action(InputMessage inputMessage) {
invoiceFileService.valid(eiInvoiceFileMessage);
}
},
NOT_VALID {
#Override public void action(InputMessage inputMessage) {
invoiceFileService.notValid(eiInvoiceFileMessage);
}
};
//+20 more values...
#Autowired
InvoiceFileService invoiceFileService;
public abstract void action(InputMessage inputMessage);
}
and I simply called the enum like this, so with different values from the enum the called function from the service would be different without writing a long switch-case.
invoice.getStatus().action(inputMessage);
Now the new requirement needs the enum to live inside a common library so it can refer to InvoiceFileService class which will be only local to my project.
I tried different options like HashMaps but the code went ugly and un-maintainable.
Is there a clean way to extend the simple enum (with only values definition) and add to it the abstract function to do stuff? maybe java 8 added some new way to do this.
You could create a wrapper enum.
public enum WrappedInvoiceStatus {
DRAFT(InvoiceStatus.DRAFT, this::someAction),
// other values
private WrappedInvoiceStatus(InvoiceStatus status, Action action) {
this.status = status;
this.action = action;
}
private interface Action { // can be one of Java default functional interfaces as well
void doSomething(InputMessage msg);
}
private void someAction(InputMessage msg) {
// behavior
}
// some plumbing required
}
Basically I’m suggesting using wrapping and lambda expressions or method references. The world of functional programming takes some getting used to. Not everyone is a fan. Your mileage may vary.
As others already said, you can not extend the enum at runtime.
But an enum can implement an interface.
So the basic idea is:
You make an interface with the action as sole abstract method:
public interface InvoiceAction {
void action(InputMessage message);
}
Your enum implements that interface
public enum InvoiceStatus implements InvoiceAction {
// ... no other changes needed
}
In all the cases where you only need to use the actual action, change InvoiceStatus to InvoiceAction. This is the most risky change. Make sure to recompile all code.
Because InvoiceAction only has one abstract method, it's a functional interface, and can be implemented with a lambda expression:
invoice.setStatus(msg -> ...);
This change is probably the most invasive change, but it might be the right thing to do - if you need a different action next time, you won't have the same problem as today.
Enum type is not extendable and implicitly final as specified in JLS:-
An enum declaration is implicitly final unless it contains at least one enum constant that has a class body (§8.9.1).
Hence a class could not extends an enum type. However you could use wrapper or adapter pattern to add additional behaviours/fields of the enum. For example:-
#Service
public class SimpleInvoiceFileService implements InvoiceFileService{
private final InvoiceStatus invoiceStatus;
public SimpleInvoiceFileService(InvoiceStatus status){
invoiceStatus = status;
}
#Override
public void draft(InputMessage input){
this.invoiceStatus.action(input);
}
#Override
public void valid(InputMessage input){
this.invoiceStatus.action(input);
}
// Add more methods to InvoiceFileService interface
// as required and override them here.
}
JLS Reference:-
https://docs.oracle.com/javase/specs/jls/se11/html/jls-8.html#jls-8.9

Adding a protected constructor to allow subclasses provide different implementations

I have the following interface (some methods ommited for simplicity):
public interface Container{
public void put(String s, Object o);
public Object get(String s);
}
and its implementation:
public class ContainerImpl implements Container{
private Map<Stirng, Object> m;
public ContainerImpl(){
m = new HashMap<>();
}
//This constructor is used in the case if a client is not satisfied
//by the HashMap, e.g. in case of Enum it's better to use EnumMap
protected ContainerImpl(Map<String, Object> m){
this.m = m;
}
public void put(String s, Object o){
m.put(s, o);
}
public Object get(String s){
m.get(s);
}
}
My question is about if providing such a protected constructor contraries to incapsulation. In fact we give to clients some knowledge that internally we use Map. If the dataStructure changed, we'll have to perform a conversion from the map passed as a parameter which may probably cause some bugs, I think.
if providing such a protected constructor contraries to incapsulation.
You are right, it does contradicts incapsulation behavior of ContainerImpl.
IMHO this is a design decision; whether class is designed to enforce incapsulation or to expose to client's/caller's for supporting varities of constructs.
For example:
A: ContainerImpl with only default-constructor implies that internal storage of Container is completely governed by it's concrete-implementation and caller cannot choose different storage.
B:
And ContainerImpl with
protected ContainerImpl(Map<String, Object> m)
implies that caller can choose the nature of Map based storage i.e. TreeMap, HashMap, LinkedHashMap or a custom implementation.
Decision on choosing one of the above approached would be based on client's need and nature.
You have responsibilities of creation, use and encapsulation of underlying Map in a single class.
If you want to follow SRP, try leaving the only public constructor which accepts Map as argument, use factories or descendants to encapsulate data:
/**
* #param m - storage model. Should not be modified after call.
*/
public ContainerImpl(Map<String, Object> m){
this.m = m;
}
/** A new instance with default storage model */
public static ContainerImpl createDefault() {
// Storage reference is isolated
return new ContainerImpl(new HashMap<>());
}
Alternatively, delete all constructors and provide:
protected abstract Map<String, Object> getStorage();
I would suggest to use something like this:
protected ContainerImpl(Map<String, Object> m){
this(); //default constructor, instantiates internal map
this.m.putAll(m); // copy all values
}
This way you will not affect encapsulation, but you will provide some convenience. As an alternative you could provide a factory method like this:
protected ContainerImpl create(Map<String, Object> m){
ContainerImpl impl = new ContainerImpl(); //default constructor, instantiates internal map
impl.m.putAll(m); // copy all values
return impl;
}

Using an enum in Java to represent keys in a ResourceBundle

I have been tinkering with this idea for a few days, and I was wondering if anyone else has thought of doing this. I would like to try and create a ResourceBundle that I can access the values with by using an enum. The benefits of this approach would be that my keys would be well defined, and hopefully, my IDE can pick up on the types and auto-complete the variable names for me. In other words, I'm after a sort of refined ListResourceBundle.
Essentially, this is what I'm after...
I have an enum that consists of various bundles set up like so:
interface Bundle {
String getBundleName();
EnumResourceBundle<??????> getEnumResourceBundle();
}
enum Bundles implements Bundle {
BUNDLE1("com.example.Bundle1", Keys.class);
private final String bundleName;
private final EnumResouceBundle<??????> bundle;
/**
* I understand here I need to do some cast with ResourceBundle.getBundle(bundleName);
* in order to have it back-track through parents properly. I'm fiddling with this
* right now using either what I specified earlier (saving bundleName and then
* retrieving the ResourceBundle as needed), and saving a reference to the
* ResourceBundle.
*/
private <E extends Enum<E> & Key> Bundles(String bundleName, Class<E> clazz) {
this.bundleName = bundleName;
this.bundle = new EnumResourceBundle<??????>(clazz);
}
#Override
public String getBundleName() {
return bundleName;
}
#Override
public EnumResourceBundle<??????> getEnumResourceBundle() {
return bundle;
}
}
interface Key {
String getValue();
}
enum Keys implements Key {
KEY1("This is a key"),
KEY2("This is another key");
private final String value;
private Keys(String value) {
this.value = value;
}
#Override
public String getKey() {
return value;
}
}
class EnumResourceBundle<E extends Enum<E> & Key> extends ResourceBundle {
// Can also store Object in case we need it
private final EnumMap<E, Object> lookup;
public EnumResourceBundle(Class<E> clazz) {
lookup = new EnumMap<>(clazz);
}
public String getString(E key) {
return (String)lookup.get(key);
}
}
So my overall goal would be to have to code look something like this:
public static void main(String[] args) {
Bundles.CLIENT.getEnumResourceBundle().getString(Keys.KEY1);
Bundles.CLIENT.getEnumResourceBundle().getString(Keys.KEY2);
// or Bundles.CLIENT.getString(Keys.KEY1);
}
I'd also like to provide support for formatting replacements (%s, %d, ...).
I realize that it isn't possible to back-track a type from a class, and that wouldn't help me because I've already instantiated Bundles#bundle, so I was wondering if I could somehow declare EnumResourceBundle, where the generic type is an enum which has implemented the Key interface. Any ideas, help, or thoughts would be appreciated. I would really like to see if I can get it working like this before I resort to named constants.
Update:
I had a thought that maybe I could also try changing EnumResourceBundle#getString(E) to take a Key instead, but this would not guarantee that it's a valid Key specified in the enum, or any enum for that matter. Then again, I'm not sure how that method would work when using a parent enum Key within a child EnumResourceBundle, so maybe Key is a better option.
I've done something like this before but I approached it the other way around and it was pretty simple.
I just created an enum translator class that accepts the enum, and then maps the enum name to the value from the property file.
I used a single resource bundle and then the translate just looked something like (from memory):
<T extends enum>String translate(T e) {
return resources.getString(e.getClass().getName()+"."+e.getName());
}
<T extends enum>String format(T e, Object... params) {
return MessageFormat.format(translate(e), params);
}
Now for any enum you can just add a string to the file:
com.example.MyEnum.FOO = This is a foo
com.example.MyEnum.BAR = Bar this!
If you want to ensure that the passed class is the correct enum for this you could either define a shared interface for those enums or you could make this into a class with the T defined on the class type and then generate instances of it for each enum you want to be able to translate. You could then do things like create a translator class for any enum just by doing new EnumFormatter(). Making format() protected would allow you to give a specific enforceable format for each enum type too by implementing that in the EnumFormatter.
Using the class idea even lets you go one step further and when you create the class you can specify both the enum that it is for and the properties file. It can then immediately scan the properties file and ensure that there is a mapping there for every value in the enum - throwing an exception if one is missing. This will help ensure early detection of any missing values in the properties file.

Understanding best use of Java Generics in this example case

Let's say I have a manufacturing scheduling system, which is made up of four parts:
There are factories that can manufacture a certain type of product and know if they are busy:
interface Factory<ProductType> {
void buildProduct(ProductType product);
boolean isBusy();
}
There is a set of different products, which (among other things) know in which factory they are built:
interface Product<ActualProductType extends Product<ActualProductType>> {
Factory<ActualProductType> getFactory();
}
Then there is an ordering system that can generate requests for products to be built:
interface OrderSystem {
Product<?> getNextProduct();
}
Finally, there's a dispatcher that grabs the orders and maintains a work-queue for each factory:
class Dispatcher {
Map<Factory<?>, Queue<Product<?>>> workQueues
= new HashMap<Factory<?>, Queue<Product<?>>>();
public void addNextOrder(OrderSystem orderSystem) {
Product<?> nextProduct = orderSystem.getNextProduct();
workQueues.get(nextProduct.getFactory()).add(nextProduct);
}
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy())
factory.buildProduct(workQueues.get(factory).poll());
}
}
Disclaimer: This code is merely an example and has several bugs (check if factory exists as a key in workQueues missing, ...) and is highly non-optimal (could iterate over entryset instead of keyset, ...)
Now the question:
The last line in the Dispatcher (factory.buildProduct(workqueues.get(factory).poll());) throws this compile-error:
The method buildProduct(capture#5-of ?) in the type Factory<capture#5-of ?> is not applicable for the arguments (Product<capture#7-of ?>)
I've been racking my brain over how to fix this in a type-safe way, but my Generics-skills have failed me here...
Changing it to the following, for example, doesn't help either:
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy()) {
Product<?> product = workQueues.get(factory).poll();
product.getFactory().buildProduct(product);
}
}
Even though in this case it should be clear that this is ok...
I guess I could add a "buildMe()" function to every Product that calls factory.buildProduct(this), but I have a hard time believing that this should be my most elegant solution.
Any ideas?
EDIT:
A quick example for an implementation of Product and Factory:
class Widget implements Product<Widget> {
public String color;
#Override
public Factory<Widget> getFactory() {
return WidgetFactory.INSTANCE;
}
}
class WidgetFactory implements Factory<Widget> {
static final INSTANCE = new WidgetFactory();
#Override
public void buildProduct(Widget product) {
// Build the widget of the given color (product.color)
}
#Override
public boolean isBusy() {
return false; // It's really quick to make this widget
}
}
Your code is weird.
Your problem is that you are passing A Product<?> to a method which expects a ProductType which is actually T.
Also I have no idea what Product is as you don't mention its definition in the OP.
You need to pass a Product<?> to work. I don't know where you will get it as I can not understand what you are trying to do with your code
Map<Factory<?>, Queue<Product<?>>> workQueues = new HashMap<Factory<?>, Queue<Product<?>>>();
// factory has the type "Factory of ?"
for (Factory<?> factory: workqueues.keySet())
// the queue is of type "Queue of Product of ?"
Queue<Product<?>> q = workqueues.get(factory);
// thus you put a "Product of ?" into a method that expects a "?"
// the compiler can't do anything with that.
factory.buildProduct(q.poll());
}
Got it! Thanks to meriton who answered this version of the question:
How to replace run-time instanceof check with compile-time generics validation
I need to baby-step the compiler through the product.getFactory().buildProduct(product)-part by doing this in a separate generic function. Here are the changes that I needed to make to the code to get it to work (what a mess):
Be more specific about the OrderSystem:
interface OrderSystem {
<ProductType extends Product<ProductType>> ProductType getNextProduct();
}
Define my own, more strongly typed queue to hold the products:
#SuppressWarnings("serial")
class MyQueue<T extends Product<T>> extends LinkedList<T> {};
And finally, changing the Dispatcher to this beast:
class Dispatcher {
Map<Factory<?>, MyQueue<?>> workQueues = new HashMap<Factory<?>, MyQueue<?>>();
#SuppressWarnings("unchecked")
public <ProductType extends Product<ProductType>> void addNextOrder(OrderSystem orderSystem) {
ProductType nextProduct = orderSystem.getNextProduct();
MyQueue<ProductType> myQueue = (MyQueue<ProductType>) workQueues.get(nextProduct.getFactory());
myQueue.add(nextProduct);
}
public void assignWork() {
for (Factory<?> factory: workQueues.keySet())
if (!factory.isBusy())
buildProduct(workQueues.get(factory).poll());
}
public <ProductType extends Product<ProductType>> void buildProduct(ProductType product) {
product.getFactory().buildProduct(product);
}
}
Notice all the generic functions, especially the last one. Also notice, that I can NOT inline this function back into my for loop as I did in the original question.
Also note, that the #SuppressWarnings("unchecked") annotation on the addNextOrder() function is needed for the typecast of the queue, not some Product object. Since I only call "add" on this queue, which, after compilation and type-erasure, stores all elements simply as objects, this should not result in any run-time casting exceptions, ever. (Please do correct me if this is wrong!)

Design pattern to handle settings in subclasses?

I have a small hierarchy of classes that all implement a common interface.
Each of the concrete class needs to receive a settings structure containing for instance only public fields. The problem is that the setting structure
has a part common to all classes
has another part that vary from one concrete class to another
I was wondering if you had in your mind any elegant design to handle this. I would like to build something like:
BaseFunc doer = new ConcreteImplementation1();
with ConcreteImplementation1 implements BaseFunc. And have something like
doer.setSettings(settings)
but have the ''settings'' object having a concrete implementation that would be suitable to ConcreteImplementation1.
How would you do that?
This may be a named design pattern, if it is, I don't know the name.
Declare an abstract class that implements the desired interface. The abstract class constructor should take an instance of your settings object from which it will extract the global settings. Derive one or more classes from the abstract class. The derived class constructor should take an instance of your settings object, pass it to the parent class constructor, then extract any local settings.
Below is an example:
class AbstractThing implements DesiredInterface
{
private String globalSettingValue1;
private String globalSettingValue2;
protected AbstractThing(Settings settings)
{
globalSettingValue1 = settings.getGlobalSettingsValue1();
globalSettingValue2 = settings.getGlobalSettingsValue2();
}
protected String getGlobalSettingValue1()
{
return globalSettingValue1;
}
protected String getGlobalSettingValue2()
{
return globalSettingValue2;
}
}
class DerivedThing extends AbstractThing
{
private String derivedThingSettingValue1;
private String derivedThingSettingValue2;
public DerivedThing(Settings settings)
{
super(settings);
derivedThingSettingValue1 = settings.getDerivedThingSettingsValue1();
derivedThingSettingValue2 = settings.getDerivedThingSettingsValue2();
}
}
Have a matching hierarchy of settings objects, use Factory to create the settings that match a specific class.
Sounds like you need a pretty standard Visitor pattern.
To put it simple, suppose, that all your properties are stored as key-value pairs in maps. And you have 3 classes in your hierarchy: A, B, C. They all implement some common interface CI.
Then you need to create a property holder like this:
public class PropertyHolder {
public Map<String, String> getCommonProperties () { ... }
public Map<String, String> getSpecialPropertiesFor (CI a) { return EMPTY_MAP; }
public Map<String, String> getSpecialPropertiesFor (A a) { ... }
public Map<String, String> getSpecialPropertiesFor (B b) { ... }
...
}
All your classes should implement 1 method getSpecialProperties which is declared in the interface CI. The implementation as simple as:
public Map<String, String> getSpecialProperties (PropertyHolder holder) {
return holder.getSpecialPropertiesFor (this);
}
I went down this route once. It worked, but after decided it wasn't worth it.
You can define a base class MyBean or something, and it has its own mergeSettings method. Every class you want to use this framework can extend MyBean, and provide its own implementation for mergeSettings which calls the superclasses mergeSettings. That way the common fields can be on the super class. If you want to get really fancy you can define and interface and abstract class to really make it pretty. And while your at it, maybe you could use reflection. anyway, mergeSettings would take a Map where the key is the property name. Each class would have its constants to related to the keys.
class MyBean extends AbstractMyBean ... {
public static final String FIELD1 = 'field1'
private String field1
public mergeSettings(Map<String, Object> incoming) {
this.field1 = incoming.get(FIELD1);
// and so on, also do validation here....maybe put it on the abstract class
}
}
Its a lot of work for setters though...
I started toying with a new pattern that I called "type-safe object map". It's like a Java Map but the values have type. That allows you to define the keys that each class wants to read and get the values in a type safe way (with no run-time cost!)
See my blog for details.
The nice thing about this is that it's still a map, so you can easily implement inheritance, notification, etc.
You could use Generics to define what kind of settings this instance need. Something like this:
public abstract class MySuperClass<T extends MySettingsGenericType>{
public MySuperClass(T settings){
//get your generic params here
}
}
public class MyEspecificClass extends MySuperClass<T extends MySettingsForThisType>{
public MySuperClass(T settings){
super(settings);
//Get your espefic params here.
}
}
//and you could use this
BaseFunc doer = new ConcreteImplementation1(ConcreteSettingsFor1);
//I dont compile this code and write in a rush. Sorry if have some error...

Categories

Resources