Design for request bucket information on client - java

I'm trying to find the best way to design the client side storage of "buckets". To explain, the server sends down info like:
{
'buckets': {
'some_cool_bucket' : 'val1',
'another_bucket' : 'name'
}
}
Where the values can be
'some_cool_bucket' : 'val1' | 'val2' | 'val3'
'another_bucket' : 'name' | 'cool' | 'other'
basically all these buckets are enums with all the possible values known to both client and server, though there aren't common constraints, like buckets can have any number of possible values (no size limit), and any naming scheme.
I'm struggling against Java to find a design I am happy with. Forget about parsing JSON, blah blah blah, from a design point of view I want to know I can store this data that meets these requirements:
Each bucket needs to be able to store a default value in case server doesn't send one down
bucket.isBucket(...) should be type safe, ie, if we use an enum here, you shouldn't be able to pass in a bucket that doesn't belong without getting an error.
Easy, simple access. Buckets.some_cool_bucket.is(val1) would be ideal.
Minimal boiler plate in adding a new bucket
Non confusing design
Ignoring these requirements, we could implement this as follows:
enum Bucket {
some_cool_bucket('val1'),
another_bucket('name');
Bucket(String default) {
[...]
}
// Assume this retrieves the stored value sent down from the server.
String getVal() {
[...]
}
boolean is(String val) {
return getVal().equals(val);
}
}
With usage Bucket.some_cool_bucket.is('val1'). Naturally, we would want to extend this by changing the type signature of is() to accept some val enum defined by some_cool_bucket. Since the values a bucket can take are not uniform, we'd have to define this inside the some_cool_bucket enum. But you can't have enums inside enums in Java.
Ok, reset. Let's try this again:
public abstract class BaseBucket<E extends Enum<E>> {
private final Class<E> mClazz;
private final E mDefaultBucket;
public BaseBucket(Class<E> clazz, E defaultBucket) {
mClazz = clazz;
mDefaultBucket = defaultBucket;
}
// Assume this retrieves the stored value sent down from the server, uses
// getName() to match with the data.
protected E getVal() {
[...]
}
protected abstract String getName();
public boolean is(E test) {
return getVal() == test;
}
}
public class SomeCoolBucket extends BaseBucket<Val> {
public SomeCoolBucket() {
super(Val.class, Val.val1);
}
#Override
public String getName() {
return "some_cool_bucket";
}
public enum Val {
val1, val2, val3;
}
}
public Buckets {
public static final SomeCoolBucket some_cool_bucket = new SomeCoolBucket();
}
Ok, this works! Great. It meets all the functional requirements, but it's cumbersome and I hate having to create a new class for each bucket. I find it hard to justify all of the code, though I believe the requirements are sound.
Does anyone have a better solution for this?

What you can do in this case is have the abstract BaseBucket class, but remove the generics bits. The base class can have an instance variable of the Enum type. To do this without generics you can use the Strategy design pattern. Using this you can make all your Enum types implement a common interface. For the sake of an example you can call this IBucketEnum. Therefore, your BaseBucket class will have an instance variable of the IBucketEnum type and will look something like this:
public abstract class BaseBucket{
private IBucketEnum enum;
//other instance vars
public String getName(){
enum.getName();
}
}
From there you can have different versions of the BaseBucket and they will have the implementations and instance variables inherited from the base one, but can be extended with additional things that you need.
Hope this helps.

Related

Patterns: Create and translate between data objects and wire formats

I was inclined to just use the mapper pattern which I use in various places in the app's code already. But I thought it might actually not be the best fit in this particular case:
The task:
I need to implement data objects according to a given specification. The specification defines multiple versions for each object type, thus I have for example a class CarV1 and CarV2 representing each version of the specification.
I need to translate these models between classes (C++ in this case, but the question is about general design) and wire formats (Json, Protocol Buffers), and vice versa.
Construction of the objects is rather simple.
As I said, I'd normally use a mapper pattern, define a mapper interface and concrete mappers to map between each format. There are two things though why I ask for your opinion in this case:
I'd use the mapper pattern only to map between two, and only two, types of formats, e.g. a database object and a model class. I already have a third format in this case, and it's possible that I have to add more formats to translate between in the near future.
The versioning adds some complexity on top of the mapping, and I think there needs to be another indirection in between.
I've read about the Translator Pattern [1], but never used it. I think it fits to some degree, but not completely.
I also considered an Abstract Factory. This would allow to create similar objects (in my case versioned objects). But it is not a good fit for mapping between object representations.
What pattern should I use, and why?
[1] http://www.iro.umontreal.ca/~keller/Layla/translator.pdf
Implementation Target
We are going to write an automatic translator. Let's say we have an object representing our wire format:
JsonObject wire_data;
For convenience, we can imagine that our JsonObject has an add_field member function:
wire_data.add_field("name", "value");
However the actual interface of the JsonObject is actually irrelevant, and the rest of this post doesn't rely on it being implemented any particular way.
We want to be able to write this function:
template<class Car>
void add_car_info(JsonObject& object, Car car) {
// Stuff goes here
}
with the following constraints:
If Car has a field, e.g. Car::getMake(), our function add_car_info should add that field to the json object automatically
If Car doesn't have a field, our function doesn't have to do anything.
Our implementation shouldn't rely on Car being derived from anything, or being a base class of anything
Our implementation should make it trivial to add new fields, without breaking backwards compatibility.
Example with four independent Car classes
Let's say you have four car classes. None of them share a base class; what fields they expose varies; and you may be adding more car classes in the future.
struct Car1
{
std::string getMake() { return "Toyota"; }
std::string getModel() { return "Prius"; }
int getYear() { return 2013; }
};
struct Car2
{
std::string getMake() { return "Toyota"; }
int getYear() { return 2017; };
};
struct Car3
{
std::string getModel() { return "Prius"; }
int getYear() { return 2017; }
};
struct Car4
{
long long getSerial() { return 2039809809820390; }
};
Now,
JsonObject wire_data;
Car1 car1;
add_field(wire_data, car1);
Should be equivilant to
Car1 car1;
wire_data.add_field("car make", car1.getMake());
wire_data.add_field("car model", car1.getModel());
wire_data.add_field("year", car1.getYear());
While
Car2 car2;
add_field(wire_data, car2);
Should be equivalent to
Car2 car2;
wire_data.add_field("car make", car2.getMake());
wire_data.add_field("year", car2.getYear());
How do we implement add_car_info in a generic way?
Figuring out which cars have which fields is a tricky problem, especially because C++ doesn't have dynamic reflection, but we can do it using static reflection (and it'll be more efficient too)!
For now, I'm going to delegate the functionality to a object representing the translator.
template<class Car>
void add_car_info(JsonObject& wire_object, Car car) {
auto translator = getCarTranslator();
// This lambda adds the inputs to wire_object
auto add_field = [&](std::string const& name, auto&& value) {
wire_object.add_field(name, value);
};
// Add the car's fields.
translator.translate(add_field, car);
}
It looks like the translator object just kicks, the can down the road, however having a translator object will make it easy to write translators for stuff other than cars.
How do we implement the magic translator?
Let's start off with getCarTranslator. With cars, there's four things we might care about: the make the model, the year, and the serial number.
auto getCarTranslator() {
return makeTranslator(READ_FIELD("car make", getMake()),
READ_FIELD("car model", getModel()),
READ_FIELD("year", getYear()),
READ_FIELD("serial", getSerial()));
}
We're using a macro here, but I promise it's the only one, and it's not a complex macro:
// This class is used to tell our overload set we want the name of the field
class read_name_t
{
};
#define READ_FIELD(name, field) \
overload_set( \
[](auto&& obj) -> decltype(obj.field) { return obj.field; }, \
[](read_name_t) -> decltype(auto) { return name; })
We're defining an overload set over two lambdas. One of them gets the object's field, and the other one of them gets the name used for serialization.
Implementing an overload set for lambdas
This is pretty straight-forward. We just create a class that inherits from both lambdas:
template <class Base1, class Base2>
struct OverloadSet
: public Base1
, public Base2
{
OverloadSet(Base1 const& b1, Base2 const& b2) : Base1(b1), Base2(b2) {}
OverloadSet(Base1&& b1, Base2&& b2)
: Base1(std::move(b1)), Base2(std::move(b2))
{
}
using Base1::operator();
using Base2::operator();
};
template <class F1, class F2>
auto overload_set(F1&& func1, F2&& func2)
-> OverloadSet<typename std::decay<F1>::type, typename std::decay<F2>::type>
{
return {std::forward<F1>(func1), std::forward<F2>(func2)};
}
Implementing a translator class using a tiny bit of SFINAE
The first step is to have a class that reads an individual field. It contains a lambda that does the reading. If we can apply the lambda, we apply it (reading the field). Otherwise, we don't apply it, and nothing happens.
template <class Reader>
class OptionalReader
{
public:
Reader read;
template <class Consumer, class Object>
void maybeConsume(Consumer&& consume, Object&& obj) const
{
// The 0 is used to dispatch it so it considers both overloads
maybeConsume(consume, obj, 0);
}
private:
// This is used to disable maybeConsume if we can't read it
template <class...>
using ignore_t = void;
// This one gets called if we can read the object
template <class Consumer, class Object>
auto maybeConsume(Consumer& consume, Object& obj, int) const
-> ignore_t<decltype(consume(read(read_name_t()), read(obj)))>
{
consume(read(read_name_t()), read(obj));
}
// This one gets called if we can't read it
template <class Consumer, class Object>
auto maybeConsume(Consumer&, Object&, long) const -> void
{
}
};
A translator takes a bunch of optional appliers, and just applies them in succession:
template <class... OptionalApplier>
class Translator : public OptionalApplier...
{
public:
// Constructors
Translator(OptionalApplier const&... appliers)
: OptionalApplier(appliers)... {}
Translator(OptionalApplier&&... appliers)
: OptionalApplier(appliers)... {}
// translate fuction
template <class Consumer, class Object>
void translate(Consumer&& consume, Object&& o) const
{
// Apply each optional applier in turn
char _[] = {((void)OptionalApplier::maybeConsume(consume, o), '\0')...};
(void)_;
}
};
Making the makeTranslator function is really simple now. We just take a bunch of readers, and use them to make optionalReaders.
template <class... Reader>
auto makeTranslator(Reader const&... readers)
-> Translator<OptionalReader<Reader>...>
{
return {OptionalReader<Reader>{readers}...};
}
Conclusion
This was a long post. There was a lot of infrastructure we had to build to get everything to work. It's really simple to use, though, and it doesn't require any knowledge about what classes we apply it on, except for what fields we're looking to use.
We can write translators for lots of stuff really easily!
Image translator example
For example, here's a translator for pictures and images that also takes into account different common names for things like the width and height of a picture.
Remember, any image class given to a translator can optionally implement any of these methods.
auto getImagesTranslator() {
// Width and height might be implemented as `getWidth` and `getHeight`,
// Or as `getRows` and `getCols`
return makeTranslator(READ_FIELD("width", getWidth()),
READ_FIELD("height", getHeight()),
READ_FIELD("width", getCols()),
READ_FIELD("height", getRows()),
READ_FIELD("location", getLocation()),
READ_FIELD("pixel format", getPixelFormat()),
READ_FIELD("size", size()),
READ_FIELD("aspect ratio", getAspectRatio()),
READ_FIELD("pixel data", getPixelData()),
READ_FIELD("file format", getFileFormat()));
}
Here's the complete implementation
why aren't' you using some serialization library for doing this? Examples would be Boost.Serialization, Google protocol buffers, etc.

Access static field of generic type

Can I require classes implementing an interface to have a certain static field or method and access/invoke that field or method through a generic type argument?
I have an interface, Arithmetical<T>, which specifies several functions like T plus(T o) and T times(T o). I have as well a Vector<N extends Arithmetical<N>> class, which is intended for vectors (of variable dimension) with components of type N. I ran into an issue, however, when trying to implement the dot product.
I want to implement the method N dot(Vector<N> o). For this, I plan to start with whatever N's zero is and iterate through both Vector<N>s' List<N>s, adding the product of each pair of elements to my total. Is there a way to specify in Arithmetical<T> that all implementing classes must have a static (and preferably final) field ZERO and start dot(Vector<N> o)'s body with something along the lines of N sum = N.ZERO;?
If not, what other approaches might there be to this problem? I want to allow 0-dimensional vectors, so I can't just begin by multiplying the vectors' first components. Is there a way to instantiate an object of a generic type, so I can merely specify a T zero() method in Arithmetical<T>?
I have a reason for not using Java's numerical types—I want to have vectors with complex components.
Here's Arithmetical:
public interface Arithmetical<T> {
public T plus(T o);
public T minus(T o);
public T negate();
public T times(T o);
public T over(T o);
public T inverse();
// Can I put a line here that requires class Complex (below) to define ZERO?
}
Vector:
public class Vector<N extends Arithmetical<N>> {
private List<N> components;
public Vector<N>(List<N> cs) {
this.components = new ArrayList<N>(cs);
}
public N dot(Vector<N> o) {
// Here's where I need help.
}
}
And Complex:
public class Complex implements Arithmetical<Complex> {
public static final Complex ZERO = new Complex(0, 0); // Can I access this value through N if <N extends Arithmetical<N>>?
private double real;
private double imag;
public Complex(double r, double i) {
this.real = r;
this.imag = i;
}
/* Implementation of Arithmetical<Complex> (and some more stuff) not shown... */
}
I'm quite new to Java (and programming in general); I will likely not understand complex (ha) explanations and workarounds.
Thanks!
(Python is a suggested tag... Huh.)
You need a "zero" for every possible implementation type. A constant in the interface won't do, because a constant cannot be overridden and must remain the same.
The solution is to add a new method to your Arithmetical interface:
public T zero();
Each implementation is forced to implement this and return its own version of zero. In this case, you're using it as a starting point for adding; it's the additive identity.
The Complex class implementation would look like this.
#Override
public Complex zero() {
return ZERO;
}
If your instances are mutable, then don't use a constant; just return new Complex(0, 0).
Another idea is to borrow from what Streams do when reduce-ing items and combining them to one single item -- take an identity value that represents the initial state, i.e. no items collected yet -- zero.
public N dot(Vector<N> o, N identity) {
N dotProduct = identity;
// Perform operations on each item in your collection
// to accumulate and return a dot product.
}
The caller will have to supply the identity value.
Complex dotProduct = vectorOfComplex.dotProduct(otherVector, new Complex(0, 0));
Can I put a line here that requires class Complex (below) to define ZERO?
No. The best you can do is to define an interface, for example:
interface ZeroProvider<A extends Arithmetical<A>> {
A zero();
}
and then supply a compatible instance of that where you need to provide a zero, for example:
class ComplexZeroProvider implements ZeroProvider<Complex> {
public Complex zero() { return new Complex(0, 0); }
}
There's something you can do sometimes using reflection in situations like this. If you put the following method in the Vector class, it will invoke a static method N.zero() (with caveats, below):
protected N zero() {
try {
Type s = getClass().getGenericSuperclass();
#SuppressWarnings("unchecked")
Class<N> n = (Class<N>) ((ParameterizedType) s).getActualTypeArguments()[0];
Method zero = n.getMethod("zero");
return n.cast(zero.invoke(null));
} catch (RuntimeException | ReflectiveOperationException x) {
// probably better to make a custom exception type
throw new IllegalArgumentException("illegal type argument", x);
}
}
However, it's important to understand what this is actually doing. This is getting the type argument from the class file of the direct superclass of this. In other words, there must actually be a superclass of this with an actual type argument (which is a class).
The usual idiom then is that you'd create all of your vectors like this:
new Vector<Complex>() {}
instead of this:
new Vector<Complex>()
Or you'd declare subclasses like this:
public class Vector<N> {
// ...
public static class OfComplex extends Vector<Complex> {
}
}
Since you need an actual superclass with a type argument which is a class, instantiations like in the following examples will fail:
new Vector<Complex>()
new Vector() // never use this anyway
new Vector() {} // never use this anyway
// also, you can't do stuff like this:
public Vector<T> copy() {
return new Vector<T>(this) {};
}
In your case I think the suggestions in the other answers are better, but I wanted to post this answer along with the proper explanation and caveats which are sometimes not included. There are cases where this technique is actually good, mainly when you have pretty tight restrictions on how the class in question is extended. Guava TypeToken will also do some of the reflection for you.
Also, this is the best Java can do at doing exactly what you're asking for (at the moment), so it's worthwhile to point out just as a comparison.

Explain of a ENUM definition in JAVA

All:
I am on first day reading team's code(the one wrote this left...):
There is one enum definition confused me so much:
/**
* Enum defines the processing stages and the order
*
*/
public enum ProcessStage {
/*
* Individual stages in the process.
* Order of processing is based on the order of listing.
*/
EXTRACT("Extraction", "EXTRACTED", "EXTRACTION_FAILED"),
ROUTE("Routing", "ROUTED", "ROUTE_FAILED"),
PUBLISH("Publishing", "PUBLISHED", "PUBLISH_FAILED");
private String detailedName;
private String successState;
private String failedState;
private ProcessStage(String detailedName, String successState, String failedState) {
this.detailedName = detailedName;
this.successState = successState;
this.failedState = failedState;
}
public String getSuccessState() {
return successState;
}
public String getFailedState() {
return failedState;
}
/**
* Factory method to provide the ProcessStage from its success or failed state value stored in DB.
* #param state
* #return ProcessStage
*/
public static ProcessStage getProcessStage(String state) {
for(ProcessStage ps: ProcessStage.values()) {
if(ps.getSuccessState().equals(state) || ps.getFailedState().equals(state)) {
return ps;
}
}
return null;
}
public String toString() {
return detailedName;
}
}
I wonder if anyone give me some simple introduction about how to read this(like what kinda syntax it uses)? The most confused part is:
EXTRACT("Extraction", "EXTRACTED", "EXTRACTION_FAILED"),
ROUTE("Routing", "ROUTED", "ROUTE_FAILED"),
PUBLISH("Publishing", "PUBLISHED", "PUBLISH_FAILED");
I do not quite understand what this means and how to use this.
And why there are a lot of methods defined inside it and how to use method with a enum variable?
Thanks
Enum
The enum declaration defines a class (called an enum type). The enum
class body can include methods and other fields. The compiler
automatically adds some special methods when it creates an enum.
enums are special type of class. Instead of creating singleton pattern using regular class or to create constants, like WeekDays, we can use enum in such places. Here
EXTRACT("Extraction", "EXTRACTED", "EXTRACTION_FAILED"),
Here EXTRACT is an enum constant meaning it is an instance of the classProcessStage and also all other enum constants(ROUTE, PUBLISH). All costants of enum are unique objects, meaning they are singleton instance created in the jvm and enum makes sure the instances are unique. You need not to put additional effort to create singleton pattern.
The above code is not only declaration, it is also calling the constructor with three String parameters to create the instance.
private ProcessStage(String detailedName, String successState, String failedState) {
this.detailedName = detailedName;
this.successState = successState;
this.failedState = failedState;
}
why there are a lot of methods defined inside it?
Since it is also a class, it can have methods like any other classes. But the restriction is, it cannot be inherited, because internally enum extens the class Enum<E extends Enum<E>> class.
how to use method with a enum variable?
EXTRACT.getFailedState() //returns "EXTRACTION_FAILED"
Keep in mind, without seeing more of the code, I can't be exactly sure what this particular enum is being used for.
So, Let's say we have a method somewhere, where a process is passed through.
public void doSomething(Process process) {}
Now, let's assume that the purpose of this method is to check the status of the process and then do some logic based upon that result. This would entail doing something like the following
public void doSomething(Process process) {
if(ProcessStage.EXTRACT.equals(process.getStage()) {
//do something here...you will have access to the methods within
//the enum
}
}
Without knowing more, this is all I can give you. I hope this gives you a slightly better understanding of what that enum is doing

How to access enum type of another class? Is there a way to use a String (a map key) as an argument of a method expecting Enum<?> type?

I'd be extremely grateful if anyone could point out what I'm doing wrong.
I have an interface IDoubleSource, which I implement in a Person class. There is a LinearRegression class with a method that takes an IDoubleSource argument, but I will pass in the Person class.
As part of the IDoubleSource interface, an enum called Variables and a method called getDoubleValue(Enum) must be defined. Below, I show how I have done this in Person, and that the enum types are used to specify switch cases in the getDoubleValue() method.
The problems:
1) In LinearRegression, there is a method computeScore((MultiKeyCoefficient)Map, IDoubleSource), where the last argument is an interface. I cannot seem to access the Variables enum of the instance of the implementation of IDoubleSource within the computeScore method, despite having the interface imported into the LinearRegression class. It just doesn't register that an IDoubleSource has an enum called Variables (though I can call the getDoubleValue() method fine). Is there anything I'm obviously doing wrong, that prevents me accessing the enum Variables?
2) The getDoubleValue(Enum) method in Person class is designed to return a double value that depends on the value of the enum Variable passed to it. By looping through the keys (which are of String type) of a (MultiKeyCoefficient)Map in the LinearRegression class, I would like to use the keys to specify the enum values that I want as an argument to getDoubleValue(Enum) in the LinearRegression class (I would like getDoubleValue() to return several different values based on the Enum values it receives in the loop). However, I cannot use the (String) key in place of the expected enum as I get a ClassCastException java.lang.String cannot be cast to java.lang.Enum. How can I use the keys of the map to specify the Enums?
I'm not very familiar with using Enum types in Java, which may be a large part of my problem.
Now the code details:
I implement the following interface:
IDOUBLESOURCE INTERFACE
public interface IDoubleSource {
public enum Variables {
Default;
}
/**
* Return the double value corresponding to the given variableID
* #param variableID A unique identifier for a variable.
* #return The current double value of the required variable.
*/
public double getDoubleValue(Enum<?> variableID);
}
by creating the class:
PERSON CLASS
public class Person implements IDoubleSource {
public enum Variables {
nChildren,
durationInCouple,
ageDiff;
}
public Person() {
...
}
public double getDoubleValue(Enum<?> variableID) {
switch ((Variables) variableID) {
case nChildren:
return getNChildren();
case durationInCouple:
return (double)getDurationInCouple();
case ageDiff:
return getAgeDiff();
default:
throw new IllegalArgumentException("Unsupported variable");
}
In another package, I have a Class:
LINEARREGRESSION CLASS
public class LinearRegression
private MultiKeyCoefficientMap map = null;
public LinearRegression(MultiKeyCoefficientMap map) {
this.map = map;
}
....
public double score(IDoubleSource iDblSrc) {
return computeScore(map, iDblSrc);
}
public static double computeScore(MultiKeyCoefficientMap coeffMap, IDoubleSource iDblSrc) {
try {
final Map<String, Double> varMap = new HashMap<String, Double>();
for (Object multiKey : coeffMap.keySet())
{
final String key = (String) ((MultiKey) multiKey).getKey(0);
Enum<?> keyEnum = (Enum<?>) key; //Throws class cast exception
double value = iDblSrc.getDoubleValue(keyEnum);
varMap.put(key, value);
}
return computeScore(coeffMap, varMap);
} catch (IllegalArgumentException e) {
System.err.println(e.getMessage());
return 0;
}
}
}
public static double computeScore(MultiKeyCoefficientMap amap, Map<String, Double> values)
{
//Do some stuff
}
I'm very grateful that you've taken the time to read through this code. Please do let me know if you have any idea what I'm doing wrong!
Many Thanks and Best Wishes,
R
The key incorrect assumption you have is that the IDoubleSource.Variables enum is connected in some way to the Person.Variables enum. They're totally unrelated. (They just happen to have the same simple name.)
When a class (like Person) implements an interface (like IDoubleSource), that class is declaring that it will provide implementations of the (non-default) methods in that interface. Any inner classes, inner enums, or inner interfaces within the implemented interface are only relevant if they appear in the signatures of one of the interface methods that must be implemented.
So you could change your interface to:
public interface IDoubleSource {
public enum Variables {
Default;
}
public double getDoubleValue(Variables variableID);
}
... but then the only legal value to pass in to any implementation of getDoubleValue is Default -- implementors of IDoubleSource can't extend the set of allowed enum values.
I think what you really want to do is to declare that implementors of IDoubleSource must declare what type of enum they deal in:
public interface IDoubleSource<T extends Variables & Enum<T>> {
public interface Variables { }
public double getDoubleValue(T variableID);
}
What you're saying here is that an implementor of the getDoubleValue() method must use some enum type as its arg, and that type must also implement the Variables interface. (If there are no meaningful methods to put in that inner inteface, you can drop it for simplicity.)
Then your implementation would look like this:
public class Person implements IDoubleSource<PersonVariables> {
public enum PersonVariables implements Variables {
nChildren,
durationInCouple,
ageDiff;
}
public double getDoubleValue(PersonVariables variableID) {
switch (variableID) { //no cast necessary here!
case nChildren:
// ...
default:
// this is now really impossible
// if the rest of your program has no unsafe casts
throw new IllegalArgumentException("Unsupported variable");
}
}
}
The last trick, then, is to enhance the signature of your computeScore method to ensure that the iDblSrc argument uses the same enum type as those found in the map:
public static <T extends IDoubleSource.Variable & Enum<T>>
double computeScore(MultiKeyCoefficientMap<T,?> coeffMap,
IDoubleSource<T> iDblSrc);
Then the keys in the map won't be Strings at all, but rather instances of the right enum type.
There are multiple problems here:
An enum declared in an interface (or class) implemented (extended) by another class is NOT overridden by the implementing class. So what you have above is two completely different enums, which happen to have the same local name. But one is IDoubleSource.Variables, with one value: IDoubleSource.Variables.Default, and the other is Person.Variables, with three values, one of which is Person.Variables.nChildren
As the OP pointed out, you cannot simply cast a String (which presumably has a value matching the name of some enum) to an enum, and have it resolve to the expected enum value.
Given these two things, and that it seems you want to select different processing for subtype specific types of things, then at worst, you could pass the string key as an argument, and then vary the logic internally. But really, you have come up with a scheme where you need to have knowledge of the subtype in order to request appropriate (supported) processing. This does not allow for the type of decoupling that is intended when using an interface/implementing class(es). You may want to review the objectives here and work out a better design.

How to implement interfaces with homographic methods in Java?

In English, a homograph pair is two words that have the same spelling but different meanings.
In software engineering, a pair of homographic methods is two methods with the same name but different requirements. Let's see a contrived example to make the question as clear as possible:
interface I1 {
/** return 1 */
int f()
}
interface I2 {
/** return 2*/
int f()
}
interface I12 extends I1, I2 {}
How can I implement I12? C# has a way to do this, but Java doesn't. So the only way around is a hack. How can it be done with reflection/bytecode tricks/etc most reliably (i.e it doesn't have to be a perfect solution, I just want the one that works the best)?
Note that some existing closed source massive piece of legacy code which I cannot legally reverse engineer requires a parameter of type I12 and delegates the I12 both to code that has I1 as a parameter, and code that has I2 as a parameter. So basically I need to make an instance of I12 that knows when it should act as I1 and when it should act as I2, which I believe can be done by looking at the bytecode at runtime of the immediate caller. We can assume that no reflection is used by the callers, because this is straightforward code. The problem is that the author of I12 didn't expect that Java merges f from both interfaces, so now I have to come up with the best hack around the problem. Nothing calls I12.f (obviously if the author wrote some code that actually calls I12.f, he would have noticed the problem before selling it).
Note that I'm actually looking for an answer to this question, not how to restructure the code that I can't change. I'm looking for the best heuristic possible or an exact solution if one exists. See Gray's answer for a valid example (I'm sure there are more robust solutions).
Here is a concrete example of how the problem of homographic methods within two interfaces can happen. And here is another concrete example:
I have the following 6 simple classes/interfaces. It resembles a business around a theater and the artists who perform in it. For simplicity and to be specific, let's assume they are all created by different people.
Set represents a set, as in set theory:
interface Set {
/** Complements this set,
i.e: all elements in the set are removed,
and all other elements in the universe are added. */
public void complement();
/** Remove an arbitrary element from the set */
public void remove();
public boolean empty();
}
HRDepartment uses Set to represent employees. It uses a sophisticated process to decode which employees to hire/fire:
import java.util.Random;
class HRDepartment {
private Random random = new Random();
private Set employees;
public HRDepartment(Set employees) {
this.employees = employees;
}
public void doHiringAndLayingoffProcess() {
if (random.nextBoolean())
employees.complement();
else
employees.remove();
if (employees.empty())
employees.complement();
}
}
The universe of a Set of employees would probably be the employees who have applied to the employer. So when complement is called on that set, all the existing employees are fired, and all the other ones that applied previously are hired.
Artist represents an artist, such as a musician or an actor. An artist has an ego. This ego can increase when others compliment him:
interface Artist {
/** Complements the artist. Increases ego. */
public void complement();
public int getEgo();
}
Theater makes an Artist perform, which possibly causes the Artist to be complemented. The theater's audience can judge the artist between performances. The higher the ego of the performer, the more likely the audience will like the Artist, but if the ego goes beyond a certain point, the artist will be viewed negatively by the audience:
import java.util.Random;
public class Theater {
private Artist artist;
private Random random = new Random();
public Theater(Artist artist) {
this.artist = artist;
}
public void perform() {
if (random.nextBoolean())
artist.complement();
}
public boolean judge() {
int ego = artist.getEgo();
if (ego > 10)
return false;
return (ego - random.nextInt(15) > 0);
}
}
ArtistSet is simply an Artist and a Set:
/** A set of associated artists, e.g: a band. */
interface ArtistSet extends Set, Artist {
}
TheaterManager runs the show. If the theater's audience judges the artist negatively, the theater talks to the HR department, which will in turn fire artists, hire new ones, etc:
class TheaterManager {
private Theater theater;
private HRDepartment hr;
public TheaterManager(ArtistSet artists) {
this.theater = new Theater(artists);
this.hr = new HRDepartment(artists);
}
public void runShow() {
theater.perform();
if (!theater.judge()) {
hr.doHiringAndLayingoffProcess();
}
}
}
The problem becomes clear once you try to implement an ArtistSet: both superinterfaces specify that complement should do something else, so you have to implement two complement methods with the same signature within the same class, somehow. Artist.complement is a homograph of Set.complement.
New idea, kinda messy...
public class MyArtistSet implements ArtistSet {
public void complement() {
StackTraceElement[] stackTraceElements = Thread.currentThread().getStackTrace();
// the last element in stackTraceElements is the least recent method invocation
// so we want the one near the top, probably index 1, but you might have to play
// with it to figure it out: could do something like this
boolean callCameFromHR = false;
boolean callCameFromTheatre = false;
for(int i = 0; i < 3; i++) {
if(stackTraceElements[i].getClassName().contains("Theatre")) {
callCameFromTheatre = true;
}
if(stackTraceElements[i].getClassName().contains("HRDepartment")) {
callCameFromHR = true;
}
}
if(callCameFromHR && callCameFromTheatre) {
// problem
}
else if(callCameFromHR) {
// respond one way
}
else if(callCameFromTheatre) {
// respond another way
}
else {
// it didn't come from either
}
}
}
Despite Gray Kemmey's valiant attempt, I would say the problem as you have stated it is not solvable. As a general rule given an ArtistSet you cannot know whether the code calling it was expecting an Artist or a Set.
Furthermore, even if you could, according to your comments on various other answers, you actually have a requirement to pass an ArtistSet to a vendor-supplied function, meaning that function has not given the compiler or humans any clue as to what it is expecting. You are completely out of luck for any sort of technically correct answer.
As practical programming matter for getting the job done, I would do the following (in this order):
File a bug report with whoever created an interface requiring ArtistSet and whoever generated the ArtistSet interface itself.
File a support request with the vendor supplying the function requiring an ArtistSet and ask them what they expect the behavior of complement() to be.
Implement the complement() function to throw an exception.
public class Sybil implements ArtistSet {
public void complement() {
throw new UnsupportedOperationException('What am I supposed to do');
}
...
}
Because seriously, you don't know what to do. What would be the correct thing to do when called like this (and how do you know for sure)?
class TalentAgent {
public void pr(ArtistSet artistsSet) {
artistSet.complement();
}
}
By throwing an exception you have a chance at getting a stack trace that gives you a clue as to which of the two behaviors the caller is expecting. With luck nobody calls that function, which is why the vendor got as far as shipping code with this problem. With less luck but still some, they handle the exception. If not even that, well, at least now you will have a stack trace you can review to decide what the caller was really expecting and possibly implement that (though I shudder to think of perpetuation a bug that way, I've explained how I would do it in this other answer).
BTW, for the rest of the implementation I would delegate everything to actual Artist and Set objects passed in via the constructor so this can be easily pulled apart later.
How to Solve For Your Specific Case
ArtistSet is simply an Artist and a Set:
/** A set of associated artists, e.g: a band. */
interface ArtistSet extends Set, Artist { }
From an OO perspective, that's not a useful declaration. An Artist is a type of noun, a "thing" that has defined properties and actions (methods).
A Set is an aggregate of things - a collection of unique elements. Instead, try:
ArtistSet is simply a Set of Artists.
/** A set of associated artists, e.g: a band. */
interface ArtistSet extends Set<Artist> { };
Then, for your particular case, the homonym methods are on interfaces that are never combined within the one type, so you have no clash and can program away...
Further, you don't need to declare ArtistSet because you aren't actually extending Set with any new declarations. You're just instantiating a type parameter, so you can replace all usage with Set<Artist>.
How to Solve For the More General Case
For this clash the method names don't even need to be homographic in the english language sense - they can be the same word with same english meaning, used in different contexts in java. Clash occurs if you have two interfaces that you wish to apply to a type but they contain the same declaration (e.g. method signature) with conflicting semantic/processing definitions.
Java does not allow you to implement the behaviour you request - you must have an alternative work-around. Java doesn't allow a class to provide multiple implementations for the same method signature from multiple different interfaces (implementing the same method multiple times with some form of qualification/alias/annotation to distinguish). See Java overriding two interfaces, clash of method names,
Java - Method name collision in interface implementation
Avoid use of Inheritence (extends or implements) and instead use Object Composition (see http://en.wikipedia.org/wiki/Composition_over_inheritance)
E.g. If you have the following
interface TV {
void switchOn();
void switchOff();
void changeChannel(int ChannelNumber);
}
interface Video {
void switchOn();
void switchOff();
void eject();
void play();
void stop();
}
Then if you have an object that is both of these things, you can combine the two in a new interface (optional) or type:
interface TVVideo {
TV getTv();
Video getVideo();
}
class TVVideoImpl implements TVVideo {
TV tv;
Video video;
public TVVideoImpl() {
tv = new SomeTVImpl(....);
video = new SomeVideoImpl(....);
}
TV getTv() { return tv };
Video getVideo() { return video };
}
How can I implement a class which has two superinterfaces having homographic methods?
In Java, a class which has two superinterfaces having homographic methods is considered to have only one implementation of this method. (See the Java Language Specification section 8.4.8). This allows classes to conveniently inherit from multiple interfaces that all implement the same other interface and only implement the function once. This also simplifies the language because this eliminates the need for syntax and method dispatching support for distinguishing between homographic methods based on which interface they came from.
So the correct way to implement a class which has two superinterfaces having homographic methods is to provide a single method that satisfies the contracts of both superinterfaces.
C# has a way to do this. How can it be done in Java? Is there no construct for this?
C# defines interfaces differently than Java does and therefore has capabilities that Java does not.
In Java, the language construct is defined to mean that all interfaces get the same single implementation of homographic methods. There is no Java language construct for creating alternate behaviors of multiply-inherited interface functions based on the compile time class of the object. This was a conscious choice made by the Java language designers.
If not, how can it be done with reflection/bytecode tricks/etc most reliably?
"It" cannot be done with reflection/bytecode tricks because the information needed to decide which interface's version of the homographic method to choose is not necessarily present in the Java source code. Given:
interface I1 {
// return ASCII character code of first character of String s
int f(String s); // f("Hello") returns 72
}
interface I2 {
// return number of characters in String s
int f(String s); // f("Hello") returns 5
}
interface I12 extends I1, I2 {}
public class C {
public static int f1(I1 i, String s) { return i.f(s); } // f1( i, "Hi") == 72
public static int f2(I2 i, String s) { return i.f(s); } // f2( i, "Hi") == 2
public static int f12(I12 i, String s) { return i.f(s);} // f12(i, "Hi") == ???
}
According to the Java language specification, a class implementing I12 must do so in such a way that C.f1(), C.f2(), and C.f12() return the exact same result when called with the same arguments. If C.f12(i, "Hello") sometimes returned 72 and sometimes returned 5 based on how C.f12() were called, that would be a serious bug in the program and a violation of the language specification.
Furthermore, if the author of class C expected some kind of consistent behavior out of f12(), there is no bytecode or other information in class C that indicates whether it should be the behavior of I1.f(s) or I2.f(s). If the author of C.f12() had in mind C.f("Hello") should return 5 or 72, there's no way to tell from looking at the code.
Fine, so I cannot in general provide different behaviors for homographic functions using bytecode tricks, but I really have a class like my example class TheaterManager. What should I do to implement ArtistSet.complement()?
The actual answer to the actual question you asked is to create your own substitute implementation of TheaterManager that does not require an ArtistSet. You do not need to change the library's implementation, you need to write your own.
The actual answer to the other example question you cite is basically "delegate I12.f() to I2.f()" because no function that receives an I12 object goes on to pass that object to a function expecting an I1 object.
Stack Overflow is only for questions and answers of general interest
One of the stated reasons to reject a question here is that "it is only relevant to an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet." Because we want to be helpful, the preferred way to handle such narrow questions is to revise the question to be more broadly applicable. For this question I have taken the approach of answering the broadly applicable version of the question rather than actually editing the question to remove what makes it unique to your situation.
In the real world of commercial programming any Java library that has a broken interface like I12 would not accumulate even dozens of commercial clients unless it could be used by implementing I12.f() in one of these ways:
delegate to I1.f()
delegate to I2.f()
do nothing
throw an exception
pick one of the above strategies on a per-call basis based on the values of some members of the I12 object
If thousands or even only a handful of companies are using this part of this library in Java then you can be assured they have used one of those solutions. If the library is not in use by even a handful of companies then the question is too narrow for Stack Overflow.
OK, TheaterManager was an oversimplification. In the real case it is too hard for me to replace that class and I don't like any of the practical solutions you've outlined. Can't I just fix this with fancy JVM tricks?
It depends on what you want to fix. If you want to fix your specific library by mapping all the calls to I12.f() and then parsing the the stack to determine the caller and choosing a behavior based on that. You can access the stack via Thread.currentThread().getStackTrace().
If you run across a caller you do not recognize you may have a hard time figuring out which version they want. For example you may be called from a generic (as was the actual case in the other specific example you gave), like:
public class TalentAgent<T extends Artist> {
public static void butterUp(List<T> people) {
for (T a: people) {
a.complement()
}
}
}
In Java, generics are implemented as erasures, meaning all type information is thrown away at compile time. There is no class or method signature difference between a TalentAgent<Artist> and a TalentAgent<Set> and the formal type of the people parameter is just List. There is nothing in the class interface or method signature of the caller to tell you what to do by looking at the stack.
So you would need to implement multiple strategies, one of which would be decompiling the code of the calling method looking for clues that the caller is expecting one class or another. It would have to be very sophisticated to cover all the ways this could happen, because among other things you have no way of knowing in advance what class it actually expecting, only that it is expecting a class that implements one of the interfaces.
There are mature and extremely sophisticated open source bytecode utilities, including one that automatically generates a proxy for a given class at runtime (written long before there was support for that in the Java language), so the fact that there isn't an open source utility for handling this case speaks volumes about the ratio of effort to usefulness in pursuing this approach.
Okay, after much research, I have another idea to fully accommodate the situation. Since you can't directly modify their code... you can force the modifications yourself.
DISCLAIMER: The example code below is very simplified. My intention is to show the general method of how this might be done, not to produce functioning source code to do it (since that's a project in itself).
The issue is that the methods are homographic. So to solve it, we can just rename the methods. Simple, right? We can use the Instrument package to achieve this. As you'll see in the linked documentation, it allows you to make an "agent" which can directly modify classes as they're loaded or re-modify them even if they've already been loaded.
Essentially, this requires you to make two classes:
An agent class which preprocesses and reloads classes; and,
A ClassFileTransformer implementation which specifies the changes you want to make.
The agent class must have either a premain() or agentmain() method defined, based on whether you want it to begin its processing as the JVM starts up or after it is already running. Examples of this are in the package documentation above. These methods give you access to an Instrumenation instance, which will allow you to register your ClassFileTransformer. So it might look something like this:
InterfaceFixAgent.java
public class InterfaceFixAgent {
public static void premain(String agentArgs, Instrumentation inst) {
//Register an ArtistTransformer
inst.addTransformer(new ArtistTransformer());
//In case the Artist interface or its subclasses
//have already been loaded by the JVM
try {
for(Class<?> clazz : inst.getAllLoadedClasses()) {
if(Artist.class.isAssignableFrom(clazz)) {
inst.retransformClasses(clazz);
}
}
}
catch(UnmodifiableClassException e) {
//TODO logging
e.printStackTrace();
}
}
}
ArtistTransformer.java
public class ArtistTransformer implements ClassFileTransformer {
private static final byte[] BYTES_TO_REPLACE = "complement".getBytes();
private static final byte[] BYTES_TO_INSERT = "compliment".getBytes();
#Override
public byte[] transform(ClassLoader loader, String className,
Class<?> classBeingRedefined, ProtectionDomain protectionDomain,
byte[] classfileBuffer) throws IllegalClassFormatException {
if(Artist.class.isAssignableFrom(classBeingRedefined)) {
//Loop through the classfileBuffer, find sequences of bytes
//which match BYTES_TO_REPLACE, replace with BYTES_TO_INSERT
}
else return classfileBuffer;
}
This is, of course, simplified. It will replace the word "complement" with "compliment" in any class which extends or implements Artist, so you will very likely need to further conditionalize it (for example, if Artist.class.isAssignableFrom(classBeingRedefined) && Set.class.isAssignableFrom(classBeingRedefined), you obviously don't want to replace every instance of "complement" with "compliment", as the "complement" for Set is perfectly legitimate).
So, now we've corrected the Artist interface and its implementations. The typo is gone, the methods have two different names, so there is no homography. This allows us to have two different implementations in our CommunityTheatre class now, each of which will properly implement/override the methods from the ArtistSet.
Unfortunately, we've now created another (possibly even bigger) issue. We've just broken all the previously-legitimate references to complement() from classes implementing Artist. To fix this, we will need to create another ClassFileTransformer which replaces these calls with our new method name.
This is somewhat more difficult, but not impossible. Essentially, the new ClassFileTransformer (let's say we call it the OldComplementTransformer) will have to perform the following steps:
Find the same string of bytes as before (the one representing the old method name, "complement");
Get the bytes before this which represent the object reference calling the method;
Convert those bytes into an Object;
Check to see if that Object is an Artist; and,
If so, replace those bytes with the new method name.
Once you've made this second transformer, you can modify the InterfaceFixAgent to accommodate it. (I also simplified the retransformClasses() call, since in the example above we perform the needed check within the transformer itself.)
InterfaceFixAgent.java (modified)
public class InterfaceFixAgent {
public static void premain(String agentArgs, Instrumentation inst) {
//Register our transformers
inst.addTransformer(new ArtistTransformer());
inst.addTransformer(new OldComplementTransformer());
//Retransform the classes that have already been loaded
try {
inst.retransformClasses(inst.getAllLoadedClasses());
}
catch(UnmodifiableClassException e) {
//TODO logging
e.printStackTrace();
}
}
}
And now... our program is good to go. It certainly wouldn't be easy to code, and it will be utter hell to QA and test. But it's certainly robust, and it solves the issue. (Technically, I suppose it avoids the issue by removing it, but... I'll take what I can get.)
Other ways we might have solved the problem:
The Unsafe API
A native method written in C
Both of these would allow you to directly manipulate bytes in memory. A solution could certainly be designed around these, but I believe it would be much more difficult and much less safe. So I went with the route above.
I think this solution could even be made more generic into an incredibly useful library for integrating code bases. Specify which interface and which method you need refactored in a variable, a command line argument, or a configuration file, and let her loose. The library that reconciles conflicting interfaces in Java at runtime. (Of course, I think it would still be better for everyone if they just fixed the bug in Java 8.)
Here's what I'd do to remove the ambiguity:
interface Artist {
void complement(); // [SIC] from OP, really "compliment"
int getEgo();
}
interface Set {
void complement(); // as in Set Theory
void remove();
boolean empty(); // [SIC] from OP, I prefer: isEmpty()
}
/**
* This class is to represent a Set of Artists (as a group) -OR-
* act like a single Artist (with some aggregate behavior). I
* choose to implement NEITHER interface so that a caller is
* forced to designate, for any given operation, which type's
* behavior is desired.
*/
class GroupOfArtists { // does NOT implement either
private final Set setBehavior = new Set() {
#Override public void remove() { /*...*/ }
#Override public boolean empty() { return true; /* TODO */ }
#Override public void complement() {
// implement Set-specific behavior
}
};
private final Artist artistBehavior = new Artist() {
#Override public int getEgo() { return Integer.MAX_VALUE; /* TODO */ }
#Override public void complement() {
// implement Artist-specific behavior
}
};
Set asSet() {
return setBehavior;
}
Artist asArtist() {
return artistBehavior;
}
}
If I were passing this object to the HR department, I'd actually give it the value returned from asSet() to hire/fire the entire group.
If I were passing this object to the Theater for a performance, I'd actually give it the value returned from asArtist() to be treated as talent.
This works as long as YOU are in control of talking to the different components directly...
But I realize that your problem is a single third-party vendor has created a component, TheaterManager, that expects one object for both of these functions and it won't know about the asSet and asArtist methods. The problem is not with the vendors that created Set and Artist, it is the vendor that combined them instead of using a Visitor pattern or just specifying an interface that would mirror the asSet and asArtist methods I made above. If you can convince your one vendor "C" to fix that interface, your world will be a lot happier.
Good luck!
Dog, I have a strong feeling you are leaving out some details that are crucial to the solution. This often happens on SO because
people need to leave out a lot of details to get the question to a reasonable size and scope,
people do not fully understand the problem and the solution (which is why they are asking for help) so they cannot be sure which details are important and which are not, and
the reason the person cannot solve the problem on their own is because they do not understand the importance of this detail, which is the same reason they left it out.
I've said in another answer what I would do about ArtistSet. But keeping the above in mind I will give you another solution to a slightly different problem. Lets say I had code from a bad vendor:
package com.bad;
public interface IAlpha {
public String getName();
// Sort Alphabetically by Name
public int compareTo(IAlpha other);
}
This is bad because you should declare a function returning a Comparator<IAlpha> to implement the sorting strategy, but whatever. Now I get code from a worse company:
package com.worse;
import com.bad.IAlpha;
// an Alpha ordered by name length
public interface ISybil extends IAlpha, Comparable<IAlpha> {}
This is worse, because it is totally wrong, in that it overrides behavior incompatibly. An ISybil orders itself by name length, but an IAlpha orders itself alphabetically, except an ISybil is an IAlpha. They were mislead by the anti-pattern of IAlpha when they could and should have done something like:
public interface ISybil extends IAlpha {
public Comparator<IAlpha> getLengthComparator();
}
However, this situation is still much better than ArtistSet because here the expected behavior is documented. There is no confusion about what ISybil.compareTo() should do. So I would create classes as follows. A Sybil class that implements compareTo() as com.worse expects and delegates everything else:
package com.hack;
import com.bad.IAlpha;
import com.worse.ISybil;
public class Sybil implements ISybil {
private final Alpha delegate;
public Sybil(Alpha delegate) { this.delegate = delegate; }
public Alpha getAlpha() { return delegate; }
public String getName() { return delegate.getName(); }
public int compareTo(IAlpha other) {
return delegate.getName().length() - other.getName().length();
}
}
and an Alpha class that works exactly like com.bad said it should:
package com.hack;
import com.bad.IAlpha;
public class Alpha implements IAlpha {
private String name;
private final Sybil sybil;
public Alpha(String name) {
this.name = name;
this.sybil = new Sybil(this);
}
// Sort Alphabetically
public int compareTo(IAlpha other) {
return name.compareTo(other.getName());
}
public String getName() { return name; }
public Sybil getSybil() { return sybil; }
}
Note that I included type conversion methods: Alpha.getSybil() and Sybil.getAlpha(). This is so I could create my own wrappers around any com.worse vendor's methods that take or return Sybils so I can avoid polluting my code or any other vendor's code with com.worse's breakage. So if com.worse had:
public ISybil breakage(ISybil broken);
I could write a function
public Alpha safeDelegateBreakage(Alpha alpha) {
return breakage(alpha.getSybil).getAlpha();
}
and be done with it, except I would still complain vociferously to com.worse and politely to com.bad.

Categories

Resources