I'm currently working on a protocol handler for a project of mine in Java. I am trying to create a maintainable and extensible API, meaning I do not want to simply hardcode in supported value types.
I have begun designing a 'protocol handler' that given a value (of a supported type) can encode that value according to the specification of the protocol, without the client worrying about the details of the translation process.
Different value types e.g. Strings or Integers necessarily have different encoding processes, but I don't want clients to worry about holding references to a different object for each possible type they may need to encode - as I said I don't want them to worry about the details.
So far I have defined a 'generic' DynamicHandler class that maintains a collection of 'specific' type aware StaticHandlers:
class DynamicHandler
{
Map<Class, StaticHandler> handlers;
<T> void handle(T value)
{
if(handlers.containsKey(value.class))
handlers.get(value.getType()).handle(value);
}
void <T> register(StaticHandler<T> handler)
{
handlers.put(T.class, handler);
}
}
The idea of this class is that a client simply passes a value they want to encode to the handle method and the DynamicHandler looks up and delegates to the StaticHandler.
interface StaticHandler<T>
{
void handle(T value);
}
Here an example of some client that uses this system:
class StringHandler implements StaticHandler<String>
{
void handle(String value)
{
...
}
}
DynamicHandler handler = new DynamicHandler();
handler.register(new StringHandler());
handler.handle("Hello World!");
I have two questions which I am struggling to find an answer to on my own:
In the DynamicHandler.register method, how can I get the type of T without having an instance of T?
Is it possible to implement the DynamicHandler type as a java.util.Map, in order to maximise compatibility with any 3rd party code clients, may use to build or otherwise process such objects?
Edit: Since DynamicHandler is essentially a Map, albeit with some generic trickery going on, is it possible to implement it as: DynamicHandler implements java.util.Map<...,...> (I'm not exactly sure what the Key and Value types should be here).
This is my first time asking a question on here, so I hope that I have been clear enough for you all. If there is anything you think needs clarifying just let me know and I will try my best.
If null values are not handled and that it is designed such that there would never be any value that belongs to multiple classes, then you could do this:
public class DynamicHandler {
Map<Class, StaticHandler> handlers;
public <T> void handle(T value) {
if(value != null) {
handlers.entrySet()
.stream()
.filter(entry ->
entry.getKey().isInstance(value))
.findAny()
.ifPresent(entry ->
entry.getValue().handle(value));
}
}
public void <T> register(StaticHandler<T> handler) {
handlers.put(handler.getHandlingClass(), handler);
}
}
interface StaticHandler<T>
{
void handle(T value);
Class<T> getHandlingClass();
}
public class StringHandler implements StaticHandler<String> {
#Override public void handle(String value) {
...
}
#Override public final Class<String> getHandlingClass() {
return String.class;
}
}
In the DynamicHandler class, how can I get the type of T without having an instance of T?
The common solution for this is to pass it a Class object:
void <T> register(StaticHandler<T> handler, Class<T> clazz)
{
handlers.put(clazz, handler);
}
Just as one example of this in a commonly used library: Gson does something similar to register JSON serializers for specific types with GsonBuilder.registerTypeHierarchyAdapter
Related
So I have some classes like BooleanLogger, IntLogger etc., which implement my own Logger interface.
This is the Logger interface:
public interface Logger {
String serialise();
Object deserialise(String value);
void setValue(Object value);
}
Here's a snippet of BooleanLogger:
public class BooleanLogger extends MutableBoolean implements Logger {
private MutableBoolean value;
// ...
#Override
public String serialise() {
return serialise(this.value.booleanValue());
}
public static String serialise(Boolean value) {
return Boolean.toString(value);
}
#Override
public Object deserialise(String value) {
return Boolean.parseBoolean(value);
}
#Override
public void setValue(Boolean value) {
this.value = new MutableBoolean(value);
logChange();
}
#Override
public void setValue(Object value) {
this.value = new MutableBoolean((Boolean) value);
logChange();
}
private void logChange() {
System.out.println(this.value); // temporary
}
}
So the basic idea is essentially to override any setter methods within MutableBoolean such that we log the new value whenever it's modified. I've implemented that part trivially so far, but that's not what I'm concerned about.
Elsewhere in my code, I have a map Map<String, Logger> loggerMap. I want to be able to get a Logger from this map and set its value, given a serialised String value. For example:
Logger logger = loggerMap.get("myLogger1");
logger.setValue(logger.deserialise(value));
It's done this way because I don't know the type of Logger I'm getting, so everything needs to work regardless.
Note the reason for this serialising/deserialising is these values are coming from Redis and hence are stored as Strings.
The problem I'm having is that in the individual loggers like BooleanLogger, it says:
'setValue(T)' in 'org.apache.commons.lang3.mutable.Mutable' clashes
with 'setValue(Object)' in 'myLogger.BooleanLogger'; both methods have
same erasure, yet neither overrides the other
The only solution I can think of is to no longer extend from MutableBoolean, MutableInt etc., and instead just copy all the methods into my own BooleanLogger, IntLogger classes. However, I have these classes for a fair few types and it would quickly become cumbersome and frustrating to do it this way. Right now I only have to deal with any methods that change the underlying value.
As far as the logic goes, I've already successfully implemented everything with my public class ArrayLogger<T> extends ArrayList<T> implements Logger {} as this is the only one that does not extend from a Mutable type that clashes on the setValue method.
EDIT: I've realised that even if I make my own class, I'll have the same issue just
'setValue(Object)' in 'myLogger.BooleanLogger' clashes with
'setValue(T)' in 'org.apache.commons.lang3.mutable.Mutable'; both
methods have same erasure, yet neither overrides the other
Assuming public class BooleanLogger implements Mutable<Boolean>, Serializable, Comparable<MutableBoolean>, Logger {}
So unless I make my own Mutable<T> type (and possibly others...), I may need a different solution.
The root problem is that your code doesn't actually make sense.
This part, specifically:
interface Logger {
void setValue(Object value);
}
You've broken the type system here. That says to me I can call setValue(whateverObjectIPlease) on any logger of any stripe and it should just work. Turns out that is incorrect - if I invoke .setValue(x) on any Logger whose actual type is BooleanLogger, and x is anything but a Boolean instance, it fails.
Hence, this is not great API. Now also consider that it fundamentally clashes with apache's Mutable hierarchy and it gets worse.
There's a second fundamental problem in your design.
Your BooleanLogger class is confused about itself and is its own factory.
Specifically, the deserialize method has nothing to do with a BooleanLogger instance. It doesn't interact with any field whatsoever, and could have been static, other than the fact that you want it to participate in class hierarchies and static methods don't.
That is what factories are for. They let you abstract non-instance parts of class structures (so, constructors, and static methods).
One way to go is to make a LoggerFactory or LoggerType interface, have exactly 1 instance for each type. You'd have something like:
interface LoggerFactory<T extends Logger> {
T deserialize(String in);
}
class BooleanLoggerFactory<BooleanLogger> {
BooleanLogger deserialize(String in) {
return new BooleanLogger(Boolean.parseBoolean(value));
}
}
Voila - you can abstract that way to your hearts content.
But, if you find that too complicated, just 'collapse' your setValue and deserialize methods.
Right now your deserialize method is lying in the sense that it says it is an instance method but it really isn't.. and your setValue method is lying in the sense that it indicates any object of any stripe will do when that isn't the case either.
But... combine the two... and both lies disappear in a puff of smoke. Behold:
interface Logger {
/** Sets the value of this logger by deserializing {#code in}. */
abstract void deserialize(String in);
// completely delete setValue. It has no business being here.
}
class BooleanLogger implements Logger {
#Override public void deserialize(String in) {
setValue(Boolean.parseBoolean(in));
}
public void setValue(boolean b) {
this.v = v;
}
}
Problem solved. If you really insist on having that setValue method be part of Logger itself, introduce generics. It was your choice to sign up to apache's Mutable type hierarchy, and it uses generics, so - you signed up for that too:
public interface Logger<T> {
String serialise();
Object deserialise(String value);
void setValue(T value);
}
public class BooleanLogger implements Logger<Boolean> {
...
#Override public void setValue(Boolean b) {
this.v = b.booleanValue();
}
}
EDIT 1: According to this, despite SomeObject<?> being indeed a superclass of SomeObject<Foo>, Class<SomeObject<?>> is NOT a superclass of Class<SomeObject<Foo>>. The question on how to tackle this specific problem still persists. (adding a method to the Message<T> class that returns Class<Message<T>>, perhaps?)
Original question:
So basically I have a generic Message<T> class that implements a well known design pattern called Command pattern (with a twist: instead of building an object with a reference, the reference is passed as argument of the execute(T objectToCallMethodsOn)) and it looks something like this:
public abstract class Message<T> {
void execute(T obj); //e.g. DoSomethingOnFooMessage implements Message<Foo> to do something on a Foo object
}
so that I can do something like:
public DoSomethingOnFooMessage implements Message<Foo> {
#Override
void execute(Foo obj) {
obj.doSomething(); //doSomething is a method of the Foo class
}
}
Now, I also tried to make a MessageProcessor class with an internal map that maps (E is a type parameter) Class<Message<E>> to a object E executableObject (like Foo in the previous example) and with two methods: a handleMessage(Message<?> msg) that should do a dynamic instanceof of the Message (hence the need for the Class<> objects that let you do a dynamic instanceof and then a dynamic cast) and look for the right executableObject in the map to call the message's execute(E obj) on the right object (if it exists, otherwise the message is discarded), and a addProcessor() to add entries of e.g. Class<Message<Foo>>, Foo to the map:
public class MessageProcessor {
private final Map<Class<Message<?>>, Object> map;
public MessageProcessor() {
map = new HashMap<>();
}
public <E> void addProcessor(Class<Message<E>> messageClass, E executable) {
map.put(messageClass, executable);
}
...
}
So far that's what I wrote but the IDE complains that Class<Message<E>> was given but Class<Message<?>> was needed in addProcessor() and I don't know why; afaik, SomeClass<?> should be a superclass of any SomeClass<SpecificClass>, why isn't it the same for Class<SomeObject<?>> and Class<SomeObject<SpecificObject>>?
Sorry for the verbose question, other than asking a thing about superclassing of generics, I am also asking you guys for (perhaps) a different, more elegant way to do what I'm trying to do, which is find the runtime class of the message so that I can call its execute() with the object that I registered with the addProcessor() as its input.
Also, I reckon this could be easily solvable with raw types (ew)
I am designing an event-driven system and am running into some basic API problems regarding generics.
I woud like all events to extend BaseEvent:
// Groovy pseudo-code
abstract BaseEvent {
Date occurredOn
BaseEvent() {
super()
this.occurredOn = new Date() // Now
}
}
And I would like all event listeners to implement some basal interface:
interface EventListener<EVENT extends BaseEvent> {
void onEvent(EVENT event)
}
So this works great for simple listeners that only handle a single type of event:
class FizzEvent extends BaseEvent { ... }
class FizzEventListener implements EventListener<FizzEvent> {
#Override
void onEvent(FizzEvent fizzEvent) {
...
}
}
But I will have some listeners that need to handle multiple types of events:
class BuzzEvent extends BaseEvent { ... }
// So then, ideally:
class ComplexListener implements EventListener<FizzEvent>,
EventListener<BuzzEvent> {
#Override
void onEvent(FizzEvent fizzEvent) {
...
}
#Override
void onEvent(BuzzEvent buzzEvent) {
...
}
}
But this produces compiler errors:
Name clash: The method onEvent(EVENT) of type EventListener has the same erasure as onEvent(EVENT) of type EventListener but does not override it
Any ideas what the solution is for handling multiple events?
The problem you're running into is called Type Erasure, which is how Java implements generics. This means that, for Java, the following lines of code:
#Override
void onEvent(FizzEvent fizzEvent) {
...
}
#Override
void onEvent(BuzzEvent buzzEvent) {
...
}
really look like this:
#Override
void onEvent(BaseEvent fizzEvent) {
...
}
#Override
void onEvent(BaseEvent buzzEvent) {
...
}
Notice that the type information has been 'erased' and only the super type BaseEvent remains as the type parameter for both methods, which causes ambiguity and won't work.
If the extends keyword had not been used, it would only see Object instead, but would still run into the same problem.
This is in contrast to C#, which uses Type Reification to implement generics and can know the difference of types at runtime.
In other words, if you ask Java whether a List<Dog> is the same kind of list as a List<Car>, Java would say "yes" because it doesn't know any better at runtime, while C# would say "no" because it retains type information.
Any ideas what the solution is for handling multiple events?
You will need to use different method names or signatures if you want to use the same listener interface (e.g. onDogBarkEvent(Dog d), onCatMeowEvent(Cat c) or perhaps create separate listener interfaces for different kinds of events (e.g. DogBarkListener, CatMeowListener).
This should point you in the right direction with a few Java options.
That aside, if you really feel strongly about your choice and are also free to choose your programming language, then you could consider taking C# for a spin and see if it works better for you.
a possible solution would be to skip generics and have an explicit "supports" method:
public FooListener implements Listener {
public <T extends BaseEvent> boolean supports(Class<T> clazz) {
//decide
}
public void handle(BaseEvent baseEvent) {
//handle
}
}
this, in combination with some abstract classes with generics for the "simple" cases, should do the trick:
private Class<S> clazz;
public Class<S> getClazz() {
if(clazz==null) {
ParameterizedType superclass =
(ParameterizedType)getClass().getGenericSuperclass();
clazz = (Class<S>) superclass.getActualTypeArguments()[0];
}
return clazz;
}
public boolean supports(Class clazz) {
return clazz!=null && clazz == getClazz();
In java 8
public class ComplexListener
{
public final EventListener<FizzEvent> fizzListener = fizzEvent ->
{
...
}
...
use complexListener.fizzListener whenever an EventListener<FizzEvent> is needed.
(Without java8, you can use anonymous class for the same effect, just more verbose.)
Another way in java8 is through method reference
public class ComplexListener
{
public void handleFizzEvent(FizzEvent fizzListener)
{
...
}
use complexListener::handleFizzEvent whenever an EventListener<FizzEvent> is needed.
In java generics, it is explicitly forbidden that an object can be both Foo<A> and Foo<B> (A!=B); i.e. Foo<A> and Foo<B> are mutually exclusive. Many reasons can be raised, but the most important one I think is because of capture conversion -- given a Foo<?> object, the compiler assumes it is a Foo<X> of a unique X. Therefore no object can be Foo<A> & Foo<B> (irrespective of reification).
I am creating a store for user preferences, and there are a fixed number of preferences that users can set values for. The names of the preferences (settings) are stored as an Enum:
public enum UserSettingName {
FOO,
BAR,
ETC
}
What I would like to be able to do is store a value type with the name so that the service will store the user's value with the correct Java type. For example, FOO might be a Long, and BAR might be a String. Up until now, we were storing all values as Strings, and then manually casting the values into the appropriate Java type. This has lead to try/catch blocks everywhere, when it makes more sense to have only one try/catch in the service. I understand that Enums cannot have generic types, so I have been playing around with:
public enum UserSettingName {
FOO(Long.class),
BAR(String.class),
ETC(Baz.class)
private Class type;
private UserSettingName(Class type) {
this.type = type;
}
public Class getType() {
return this.type;
}
}
I have a generic UserSetting object that has public T getSettingValue() and public void setSettingValue(T value) methods that should return and set the value with the correct type. My problem comes from trying to specify that generic type T when I create or retrieve a setting because I can't do something like:
new UserSetting<UserSettingName.FOO.getType()>(UserSettingName.FOO, 123L)
Sorry if this isn't exactly clear, I can try to clarify if it's not understood.
Thanks!
UPDATE
Both the setting name and value are coming in from a Spring MVC REST call:
public ResponseEntity<String> save(#PathVariable Long userId, #PathVariable UserSettingName settingName, #RequestBody String settingValue)
So I used the Enum because Spring casts the incoming data automatically.
Firstly you have to step back and think about what you're trying to achieve, and use a standard pattern or language construct to achieve it.
It's not entirely clear what you're going after here but from your approach it almost certainly looks like you're reinventing something which could be done in a much more straightforward manner in Java. For example, if you really need to know and work with the runtime classes of objects, consider using the reflection API.
On a more practical level - what you're trying to do here isn't possible with generics. Generics are a compile-time language feature - they are useful for avoiding casting everything explicitly from Object and give you type-checking at compilation time. You simply cannot use generics in this way, i.e. setting T as some value UserSettingName.Foo.getType() which is only known at runtime.
Look how it done by netty:
http://netty.io/wiki/new-and-noteworthy.html#type-safe-channeloption
They done it by using typed constants:
http://grepcode.com/file/repo1.maven.org/maven2/io.netty/netty-all/4.0.0.Beta1/io/netty/channel/ChannelOption.java#ChannelOption
EDIT:
public interface ChannelConfig {
...
<T> boolean setOption(ChannelOption<T> option, T value);
...
}
public class ChannelOption<T> ...
public static final ChannelOption<Integer> SO_TIMEOUT =
new ChannelOption<Integer>("SO_TIMEOUT");
...
}
EDIT2: you can transform it like:
class Baz {}
class UserSettingName<T> {
public static final UserSettingName<Baz> ETC = new UserSettingName<Baz>();
}
class UserSetting {
public <T> UserSetting(UserSettingName<T> name, T param) {
}
}
public class Test {
public static void main(String[] args) {
new UserSetting(UserSettingName.ETC, new Baz());
}
}
Enums are not the answer here. If you find yourself repeating code everywhere you could just create a utility class and encapsulate all the try/catch logic there. That would cut down on your code redundancy without majorly impacting your current code.
public class Util
{
public static MyObject getObjectFromString(String s)
{
try
{
return (MyObject)s;
}
catch(Exception e)
{
return null;
}
}
}
Then use as follows:
MyObject myObj = Util.getObjectFromString(string);
I've been reading Effective Java and decided to try to put some of what I've learned into action. I'm trying to effectively create a Multimap<?, Condition<?> > where the wild card will be the same type for both the key and the value, but it will be different, distinct types.
Here is the item from the book I'm looking at: Item 29
I'm not trying to fully replicate it. I realize the big difference is the key does not represent the value directly as per the link. In mine, the key represents the generic type of the value.
So I will do mmap.put(Class<Integer>, ConditionMapping<Integer>)
when I do the get I don't have the generic type of the ConditionMapping, so I get the unchecked cast warning.
I have a get method that I want to have the signature <T> List<Condition <T> >(Class<T> type)
Due to type erasure, is my only option to make sure the condition.value is of type T and building a new list of objects?
I could just ignore the unchecked cast warning, but I'm just trying not to. Any suggestions? Tips? Tricks?
There is no way to express that the two wildcards should capture the same type. See this question for a similar situation and a number of possible solutions.
If you make your interface extend Multimap<Void, Condition<?>> it allows your user to call some of the methods that do not rely on type safety (e.g. containsKey) but not to add entries (bypassing your type-checked proxy methods) unless they use unchecked casts.
interface ConditionMapBase<T> extends Multimap<T, Condition<?>> {
}
interface ConditionMap extends ConditionMapBase<Void> {
<T>boolean putCondition(T key, Condition<T> value);
<T>Collection<Condition<T>> getConditions(T key);
}
class ConditionMapImpl
extends ForwardingMultimap<Void, Condition<?>>
implements ConditionMap {
ConditionMapImpl() {
delegate = HashMultimap.create();
}
#SuppressWarnings("unchecked")
#Override
protected Multimap<Void, Condition<?>> delegate() {
return (Multimap<Void, Condition<?>>) (Multimap<?, ?>) delegate;
}
private final Multimap<Object, Condition<?>> delegate;
#SuppressWarnings("unchecked")
#Override
public <T> Collection<Condition<T>> getConditions(T key) {
return (Collection<Condition<T>>) (Collection<?>) ((ConditionMapBase<T>) this).get(key);
}
#SuppressWarnings("unchecked")
#Override
public <T> boolean putCondition(T key, Condition<T> value) {
return ((ConditionMapBase<T>) this).put(key, value);
}
}
You could make a MyClass and then pass your own type to it, and ecapsulate the Multimap inside that. Template impossibilities in Java can often be solved by adding another layer, so to speak, and templating a class around what you really want, since you can get a "T" type that way, which you can then use for Lists or Maps, and guarantee that it is the same for multiple templates from then on.
This might be a step in the right direction.
<Multimap<Class<?>, Condition<?>>