Casting Proxies - Getting ClassCastException - java

I'm getting some weirdness when I'm casting a Dynamic Proxy Class to the object I want it to be. At runtime, under certain conditions, I receive a ClassCastException.
In order to explain this better, here are the definitions for the classes/interfaces I want to use. Brackets have been put around any extended interfaces that (should be) irrelevant.
public interface CommandSender (extends Permissible)
public interface ConsoleCommandSender extends CommandSender, (Conversable)
public interface Player extends (HumanEntity, Conversable), CommandSender, (OfflinePlayer, PluginMessageRecipient)
Full Javadocs can be found here: http://jd.bukkit.org/apidocs/org/bukkit/command/CommandSender.html
Now, here is the code for my proxy class:
public class CommandSignsMessagingProxy implements InvocationHandler {
private Object sender;
private Object receiver;
private boolean silent;
public static Object newInstance(Object proxy) {
return newInstance(proxy, proxy, false);
}
public static Object newInstance(Object proxy, boolean silent) {
return newInstance(proxy, proxy, silent);
}
public static Object newInstance(Object sender, Object receiver) {
return newInstance(sender, receiver, false);
}
public static Object newInstance(Object sender, Object receiver, boolean silent) {
return Proxy.newProxyInstance(
sender.getClass().getClassLoader(),
sender.getClass().getInterfaces(),
new CommandSignsMessagingProxy(sender, receiver, silent));
}
private CommandSignsMessagingProxy(Object sender, Object receiver, boolean silent) {
this.sender = sender;
this.receiver = receiver;
this.silent = silent;
}
// Is called whenever a method is invoked
public Object invoke(Object p, Method m, Object[] args) throws Throwable {
Object result = null;
try {
String name = m.getName();
// If the receiver is being sent a message, only do so if the silent flag is not set
if (name == "sendMessage" || name == "sendRawMessage") {
if (!silent && receiver != null)
result = m.invoke(receiver, args);
} else {
result = m.invoke(sender, args);
}
} catch (InvocationTargetException e) {
throw e.getTargetException();
} catch (Exception e) {
throw new RuntimeException("Unexpected invocation exception: " + e.getMessage());
}
return result;
}
}
And here is a fully working instance of the class:
Player proxy = (Player)CommandSignsMessagingProxy.newInstance(player, false);
proxy.sendMessage("Hi! Silent is turned off, so you can see this!");
proxy.setOp(true);
proxy.other_stuff();
Yet, this one doesn't work:
ConsoleCommandSender ccs = plugin.getServer().getConsoleSender();
CommandSender cs = (CommandSender)CommandSignsMessagingProxy.newInstance(ccs, false);
At run time, this example would produce the following:
java.lang.ClassCastException: $Proxy18 cannot be cast to org.bukkit.command.CommandSender

The created proxy class need to pass the interfaces it suppose to implement,
return Proxy.newProxyInstance(
sender.getClass().getClassLoader(),
sender.getClass().getInterfaces(),
new CommandSignsMessagingProxy(sender, receiver, silent));
failure seems to happen because CommandSender interface may not be returned from the call sender.getClass().getInterfaces() method. So try to see if it properly passes by debugging. If not try sending the interface manually to the method and see if it works.

Related

implement abstract method without calling it directly

I have an abstract class
public abstract class Sender {
private IThrottler throttler;
public final Object sendMessage(String smsText, String smsSenderName, String contactNumber) throws Exception {
tdLogger.info("sending request >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
String messageId = (String) sendSMS(smsText, smsSenderName, contactNumber);
tdLogger.info("request sent <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
return messageId;
}
public final Object throttleMessage(String smsText, String smsSenderName, String contactNumber) throws Exception {
if (throttler != null) {
throttler.acquire();
tdLogger.info("sending request >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>");
String messageId = (String) sendSMS(smsText, smsSenderName, contactNumber);
tdLogger.info("request sent <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<");
return messageId;
} else {
throw new Exception("throttler is not initialized");
}
}
public abstract Object send(String smsText, String smsSenderName, String contactNumber) throws Exception;
}
I have another class SenderImpl that which extends Sender
is there a way to force implementing the function send without giving the ability to call it directly and only be able to call sendMessage and throttleMessage to force running certain logic?
You can make the abstract send method protected so that only subclasses and classes in the same package can call it. This achieves what you intend even if it can be circumvented by placing a class in the same package.

Java: message system needs to be able to pass various objects

I'm writing a messaging system to queue actions for my program to execute. I need to be able to pass various objects by the messages. I currently have a Msg object that accepts (Action enum, Data<?>...object). The Data object is intended to be a wrapper for any object I might pass.
Currently the Data object uses this code, with generics:
public class Data<T> {
private T data;
public Data(T data){
this.data = data;
}
public T getData(){
return data;
}
}
The Msg object takes Data<?>... type, so Msg has a Data<?>[] field.
If getData() is called on a Data<?> object, it returns the Object type. Obviously not ideal.
I need to be able to pass, say, Image objects as well as String objects. I'm certain there's a better way of passing arbitrary data.
The reason you're having trouble is that you're trying to get the static typing system of Java to do something that it can't. Once you convert from a Data<T> to a Data<?>, whatever T was is effectively lost. There's no clean way to get it back.
The quickest way to get it to work (from what you have right now) is to start throwing casts everywhere, like this:
Data<?> d = new Data("Hello");
String contents = (String)d.getData();
This is kind of a terrible idea, so let's go back to the drawing board.
If (ideally), you have all of the types you could ever need ahead of time (i.e. every Data is either a String or an Image or an Integer), then you can pretty easily (though it's a bit tedious) define a Sum type (aka a union if you're coming from C) of the different types of data you'll have to handle. As a class invariant, we assume that exactly one of the fields is non-null, and the rest are null. For this example I'll assume it can be either a String, an Image, or an Integer, but it's fairly simple to add or remove types from Data as necessary.
public class Data {
private Image imgData;
private String stringData;
private Integer intData;
public Data(Image img) {
this.imgData = img;
}
public Data(String stringData) {
this.stringData = stringData;
}
public Data(Integer intData) {
this.intData = intData;
}
public boolean isImage() {
return imageData != null;
}
public boolean isInteger() {
return intData != null;
}
public boolean isString() {
return stringData != null;
}
public Image asImage() {
if(! isImage()) throw new RuntimeException();
return imgData;
}
public Image asString() {
if(! isString()) throw new RuntimeException();
return stringData;
}
public Image asInt() {
if(! isInt()) throw new RuntimeException();
return intData;
}
}
One necessary side effect is that we cannot wrap null without causing exceptional behavior. Is this is desired, it isn't too difficult to modify the class to allow for it.
With this Data class, it's pretty easy to do if-else logic to parse it.
Data d = ....... //Get a data from somewhere
if(d.isImage()) {
Image img = d.asImage();
//...
} else if (d.isString()) {
String string = d.asString();
//...
} else if (d.isInteger()) {
Integer i = d.asInt();
//...
} else {
throw new RuntimeException("Illegal data " + d + " received");
}
If you call getData().getClass() you will get the class or type that was passed, which doesn't seem to me to be the same as an Object. You might not know what you are getting, but you can either find out or define a common interface for everything you might pass. You could for example, call toString() or getClass() on anything passed. Your question is that you are passing any conceivable object, so my question is what are you going to do with it? If you are going to serialize it into a database you don't need know anything about what type it is, otherwise you can test it or call a common interface.
public class PlayData {
class Msg {
private List<Data<?>> message = new ArrayList<Data<?>>();
public void addData(Data<?> datum) { message.add(datum); }
public void printTypes() { for ( Data<?> datum: message ) { System.out.println(datum.getData().getClass()); } }
}
class Data<T> {
private T value;
public Data(T value) { this.value = value; }
public T getData() { return value; }
}
class Listener {
public void receive(Msg msg) { msg.printTypes(); }
}
class Sender {
private Listener listener;
public Sender(Listener listener) { this.listener = listener; }
public void send(Msg msg) { listener.receive(msg); }
}
class MyPacket {
int i;
public MyPacket(int i) { this.i = i; }
}
public static void main(String[] args) throws Exception { new PlayData().run(); }
public void run() throws Exception {
Sender sender = new Sender(new Listener());
Msg msg = new Msg();
msg.addData(new Data<String>("testing") );
msg.addData(new Data<MyPacket>(new MyPacket(42)) );
sender.send(msg);
}
}

How to get equals and hashcode to work with Java RMI?

I'm trying to learn Java RMI and I need to compare some objects. Specifically, I want to know if a set already contains an element, but it doesn't detect that an object is already present in the set. I don't have any other communication problems with RMI in general.
I've tried overriding hashcode() and equals(Object obj) in my remote object implementation, which is what I have to do from my understanding.
Here's some code:
public class ChatClientImpl extends UnicastRemoteObject implements ChatClient {
private static final long serialVersionUID = 3056117484716596895L;
private String id = null;
// some other stuff...
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || !(obj instanceof ChatClientImpl)) {
return false;
}
ChatClientImpl other = (ChatClientImpl) obj;
return this.id.equals(other.id);
}
#Override
public int hashCode() {
return this.id.hashCode();
}
}
Set#contains and List#contains just don't work. Is there some other trick to this?
Some more complete code:
public void processMessage(MessageImpl inMessage) throws java.rmi.RemoteException {
// check the message to see if we have processed it before - discard if so
if( this.processedMessages.contains(inMessage.id) ) {
System.err.println("Ignoring duplicate message: " + inMessage.id);
return;
}
else {
System.out.println("Processing message: " + inMessage.id);
this.processedMessages.add(inMessage.id);
System.out.println(this.processedMessages.size() + " messages have been processed");
}
// update the GUI display with the new message
this.gui.updateDisplay(inMessage);
// add this client to the set of clients that have seen the message
inMessage.addRecipient(this);
// pass the message on to one of the clients that haven't seen it yet
sendMessage(inMessage);
}
private void sendMessage(MessageImpl msg) {
Iterator<ChatClient> clientIterator;
try {
// list of all known clients fetched from a server via RMI call
clientIterator = server.getClients().iterator();
} catch (RemoteException e) {
// log the error...
return;
}
// clients that have already seen the message
Set<ChatClient> alreadyPassedThru = msg.getRecipients();
boolean messageSent = false;
while ( ! messageSent && clientIterator.hasNext() ){
ChatClient knownClient = clientIterator.next();
try {
// clients that are in alreadyPassedThru are NOT detected...
if ( alreadyPassedThru.contains(knownClient) ){
System.out.println("Skipping client that has already seen the message: " + knownClient.getName());
} else {
knownClient.processMessage(msg);
System.out.println("Message has been sent to " + knownClient.getName());
messageSent = true;
}
} catch (RemoteException e) {
// client couldn't be contacted
clientIterator.remove();
}
}
}
It's worth mentioning that if I replace the code if ( alreadyPassedThru.contains(knownClient) ) (which is where the problem is) with some code that iterates over the set alreadyPassedThru and manually checks if any of the elements match knownClient by comparing their respective clientName variables, then everything works fine.
The MessageImpl code:
public class MessageImpl implements java.io.Serializable, Message {
private static final long serialVersionUID = 8914588083609635659L;
/**
* The globally unique identifier for this message
*/
public final GUID id;
/**
* All remote clients that have seen this message so far
*/
public final Set<ChatClient> passedThrough = new HashSet<ChatClient>();
/**
* The content of the message.
*/
private String messageContent = null;
/**
* The client who created the object
*/
private ChatClient author = null;
/**
* Create a new Message instance.
*/
public MessageImpl(ChatClient auth, String msg) {
this.id = new GUID(auth);
this.author = auth;
this.messageContent = msg;
addRecipient(auth); // the author has seen the message
}
#Override
public void addRecipient(ChatClient client) {
this.passedThrough.add(client);
}
#Override
public Set<ChatClient> getRecipients() {
return this.passedThrough;
}
#Override
public String getContent() {
return this.messageContent;
}
public String getSource() {
try {
return this.author.getName();
} catch (Exception e) {
return "[Unknown User]";
}
}
}
Just to clarify the difference between when the application works and when it doesn't work: if I replace this:
if ( alreadyPassedThru.contains(knownClient) ){...
where alreadyPassedThru is a HashSet<ChatClient> and knownClient is a ChatClient with this code:
// RMI call on ChatClient - simply returns clientName field
String knownClientName = knownClient.getName();
for (ChatClient client : alreadyPassedThru) {
if ( client.getName().equals(knownClientName) ){
return true;
}
}
...then it works.
You should try using instanceof instead of the getClass() method.
if (obj == null || !(obj instanceof MyRemote)) {
...
}
This is, at the very least, more efficient and may be the cause of your issue.
You might also want to consider simplifying your logic a bit. Right now, you have 3 return points in your code and the intent is not immediately clear. Try this:
public boolean equals(Object obj) {
if (obj instanceof MyRemoteImpl) {
MyRemoteImpl other = (MyRemoteImpl) obj;
return this.id.equals(other.id);
}
return false;
}
They already work with Java RMI.
Remote objects and their stubs have the same hashcodes and equals() behaviour by default if the remote objects extend UnicastRemoteObject.
However you've broken that by overriding hashCode() and equals().
Just remove those overrides.
Try doing as follows:
public class ChatClientImpl extends UnicastRemoteObject implements ChatClient {
private static final long serialVersionUID = 3056117484716596895L;
private String id = null;
// some other stuff...
#Override
public boolean equals(Object obj) {
if (super.equals(obj)) {
//Should also return true for stubs pointing to this
return true;
}
if (obj == null || !(obj instanceof ChatClient)) { //Check against the interface
return false;
}
//Only use the interface. obj might be a stub, not only an impl.
ChatClient other = (ChatClient) obj;
return getName().equals(obj.getName());
}
#Override
public int hashCode() {
return getName().hashCode();
}
}
I am definitely not sure this will work, but the specification for RemoteObject.equals makes me hope so.
EDIT
This can't work, because equals and hashCode are computed directly on the stub, regardless of what you implemented on your server.
This leaves you with two options:
(which I suggest) rely on the default equals. The client ID should be unique, and there should be no two clients with the same ID. That's clearly not the case in your implementation, because you're using an additional id field, implying the identity of an instance is not enough. I think it should be.
Wrap your ChatClients in a CustomHashChatClient and use a Set<CustomHashChatClient>, with CustomHashChatClient computing a custom hash, based on the object name, id, or whatever you want (of course, you need to swallow the exceptions or fail on them, which makes this a not-so-good idea).

Java8 dynamic proxy and default methods

Having a dynamic proxy for an interface with default methods, how do I invoke a default method? By using something like defaultmethod.invoke(this, ...) you just get your proxy invocation handler called (Which is somehow correct, cause you have no implementing class for this interface).
I have a workaround using ASM to create a class implementing the interface and delegating such calls to an instance of this class. But this is not a good solution, especially if the default method calls other interface methods (you get a delegator ping-pong). The JLS is surprisingly silent about this question...
Here a small code example:
public class Java8Proxy implements InvocationHandler {
public interface WithDefaultMethod {
void someMethod();
default void someDefaultMethod() {
System.out.println("default method invoked!");
}
}
#Test
public void invokeTest() {
WithDefaultMethod proxy = (WithDefaultMethod) Proxy.newProxyInstance(
WithDefaultMethod.class.getClassLoader(),
new Class<?>[] { WithDefaultMethod.class }, this);
proxy.someDefaultMethod();
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// assuming not knowing the interface before runtime (I wouldn't use a
// proxy, would I?)
// what to do here to get the line printed out?
// This is just a loop
// method.invoke(this, args);
return null;
}
}
You can use the MethodHandles type in your InvocationHandler. This code is copied from Zero Turnaround.
Constructor<MethodHandles.Lookup> constructor;
Class<?> declaringClass;
Object result;
if (method.isDefault()) {
declaringClass = method.getDeclaringClass();
constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
constructor.setAccessible(true);
result = constructor.
newInstance(declaringClass, MethodHandles.Lookup.PRIVATE).
unreflectSpecial(method, declaringClass).
bindTo(proxy).
invokeWithArguments(args);
return(result);
}
The accepted answer uses setAccessible(true) to break into MethodHandles.Lookup, something that is restricted in Java 9 and beyond. This mail describes a JDK change that works for Java 9 or later.
It is possible to get this to work on Java 8 (and later) if you can get the writer of the interface to call your utility with an instance of MethodHandles.Lookup created in the interface (so it gets the permission to access the default methods of the interface):
interface HelloGenerator {
public static HelloGenerator createProxy() {
// create MethodHandles.Lookup here to get access to the default methods
return Utils.createProxy(MethodHandles.lookup(), HelloGenerator.class);
}
abstract String name();
default void sayHello() {
System.out.println("Hello " + name());
}
}
public class Utils {
static <P> P createProxy(MethodHandles.Lookup lookup, Class<P> type) {
InvocationHandler handler = (proxy, method, args) -> {
if (method.isDefault()) {
// can use unreflectSpecial here, but only because MethodHandles.Lookup
// instance was created in the interface and passed through
return lookup
.unreflectSpecial(method, method.getDeclaringClass())
.bindTo(proxy)
.invokeWithArguments(args);
}
return ...; // your desired proxy behaviour
};
Object proxy = Proxy.newProxyInstance(
type.getClassLoader(), new Class<?>[] {type}, handler);
return type.cast(proxy);
}
}
This approach won't handle all Java 8 use cases, but it did handle mine.
Since jdk-16 this is supported in a native way, via invokeDefault.
To your example, this would be done as:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class InvocationHandlerTest {
public static void main(String[] args) {
WithDefaultMethod proxy = (WithDefaultMethod) Proxy.newProxyInstance(
WithDefaultMethod.class.getClassLoader(),
new Class<?>[] { WithDefaultMethod.class }, new Java8Proxy());
proxy.someDefaultMethod();
}
interface WithDefaultMethod {
void someMethod();
default void someDefaultMethod() {
System.out.println("default method invoked!");
}
}
static class Java8Proxy implements InvocationHandler {
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoked");
InvocationHandler.invokeDefault(proxy, method, args);
return null;
}
}
}
But you do not need an explicit implementation of the interface that you need, this can be done slightly different:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class InvocationHandlerTest {
public static void main(String[] args) {
WithDefaultMethod proxy = (WithDefaultMethod) Proxy.newProxyInstance(
WithDefaultMethod.class.getClassLoader(),
new Class<?>[] { WithDefaultMethod.class },
(o, m, params) -> {
if (m.isDefault()) {
// if it's a default method, invoke it
return InvocationHandler.invokeDefault(o, m, params);
}
return null;
});
proxy.someDefaultMethod();
}
interface WithDefaultMethod {
void someMethod();
default void someDefaultMethod() {
System.out.println("default method invoked!");
}
}
}
I wrote up a blog entry detailing the different approaches that must be used for Java 8 and 9+: http://netomi.github.io/2020/04/17/default-methods.html
It includes code from the spring framework to handle the different cases in a clean and efficient way.
This is annoyingly stupid counter-intuitive behaviour, which I assert is a bug in method#invoke(Object,Object[]), because you can't keep things simple in an InvocationHandler, like:
if (method.isDefault())
method.invoke(proxy, args);
else
method.invoke(target, args); // to call a wrapped object
So have to do a special lookup for a MethodHandle, and bind to proxy, to call, it.
I refined the McDowell provided code as follows (simplified):
private static final Constructor<MethodHandles.Lookup> lookupConstructor;
static {
try {
lookupConstructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
lookupConstructor.setAccessible(true);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
private static MethodHandle findDefaultMethodHandle(Class<?> facadeInterface, Method m) {
try {
Class<?> declaringClass = m.getDeclaringClass();
// Used mode -1 = TRUST, because Modifier.PRIVATE failed for me in Java 8.
MethodHandles.Lookup lookup = lookupConstructor.newInstance(declaringClass, -1);
try {
return lookup.findSpecial(facadeInterface, m.getName(), MethodType.methodType(m.getReturnType(), m.getParameterTypes()), declaringClass);
} catch (IllegalAccessException e) {
try {
return lookup.unreflectSpecial(m, declaringClass);
} catch (IllegalAccessException x) {
x.addSuppressed(e);
throw x;
}
}
} catch (RuntimeException e) {
throw (RuntimeException) e;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private static class InvocationHandlerImpl implements InvocationHandler {
private final Class<?> facadeInterface;
private Object invokeDefault(Object proxy, Method method, Object[] args) throws Throwable {
MethodHandle mh = findDefaultMethodHandle(facadeInterface, m);
return mh.bindTo(proxy).invokeWithArguments(args);
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (method.isDefault()) {
return invokeDefault(proxy, method, args);
}
// rest of code method calls
}
}
facadeInterface is the interface being proxied, which declares the default method, it will probably be possible to use super-interface default methods too.
Non-toy code should do this lookup before invoke is called, or at least cache the MethodHandle.

Check class type

How i can check if a class is of a determinated type for example:
// PacketHandler.java
public interface PacketHandler<T> {
public void handlePacket(T packet);
}
// PacketReader.java
public void read() {
Packet packet = // Read some input
for(PacketHandler packetHandler : packetHandlers) {
if (packetHandler is the type of packet) { // here is the problem
packetHandler.handlePacket(packet);
}
}
}
public void registerHandler(PacketHandler<?> packetHandler) {
packetHandlers.add(packetHandler);
}
// Main
packetReader.registerHandler(new PacketHandler<RandomPacket>() {
public void handlePacket(RandomPacket packet) {
// I handle the packet
}
});
I know that this question maybe seems stupid;
but how to solve this problem?
**Edit*****
Jon Skeet, so the class should be:
public class RandomClass implements PacketHandler {
public boolean handlePacket(Packet packet) {
if (packet instanceof PacketThatThisClassHandle) {
//handle with casting
return true;
} else {
return false;
}
}
}
Unfortunately Java generics use type erasure, meaning that at execution time, any particular PacketHandler<T> is just PacketHandler as far as the VM is concerned.
You may want to change your code to:
public interface PacketHandler {
// The parameter type can be Object if you really want
boolean tryHandlePacket(Packet packet);
}
... and make a PacketHandler just return false if it doesn't know how to handle a particular packet type.
Then you can just use:
for (PacketHandler handler : handlers) {
if (handler.tryHandlePacket(packet)) {
break;
}
}
(That's assuming you only want a single handler to actually handle any packet type.)
If you still want a generic interface, you'd either need a boolean handlesPacket(Packet) method, or possibly a Class<T> getPacketType() method. Either way it's still going to be a pain in terms of casting the packet to the right type...
If you have lots of packet handlers, you could potentially create an abstract base class:
public abstract class AbstractPacketHandler<T extends Packet>
implements PacketHandler {
private final Class<T> packetType;
protected AbstractPacketHandler(Class<T> packetType) {
this.packetType = packetType;
}
protected abstract void handlePacket(T packet);
public boolean tryHandlePacket(Packet packet) {
if (!packetType.isInstance(packet)) {
return false;
}
handlePacket(packetType.cast(packet));
return true;
}
}
Then you can write:
public class FooPacketHandler extends PacketHandler<Foo> {
public FooPacketHandler() {
super(Foo.class);
}
protected void handlePacket(Foo packet) {
...
}
}
Type erasure won't make this attempt easy. The mapping part it's quite easy, you can use a HashMap. But the problem is that the handlePacket method accepts a parameter of type T, which forces you to cast the object to that type before passing it to the handler.
To avoid relaxing the constraint you could use a two level invokation, something like:
interface Packet { }
class ConcretePacket implements Packet { }
HashMap<Class<?>, PacketHandler<?>> mapping =
new HashMap<Class<?>, PacketHandler<?>>();
public abstract class PacketHandler<T extends Packet> {
PacketHandler(Class<T> clazz) {
mapping.put(clazz, this);
}
public final void handlePacket(Packet packet) {
doHandlePacket((T)packet);
}
public abstract void doHandlePacket(T packet);
}
public class ConcretePacketHandler extends PacketHandler<ConcretePacket>
{
ConcretePacketHandler()
{
super(ConcretePacket.class);
}
public void doHandlePacket(ConcretePacket s) {
// whatever
}
}
public void receivedPacket(Packet packet) {
PacketHandler<?> handler = mapping.get(packet.getClass());
if (handler != null)
handler.handlePacket(packet);
}
Mind that this could not work in certain situations (maybe with different classloaders involved) and that, to manage subclasses of PacketManager, you will need to find a better way to retrieve the correct handler, eg by using a List<Pair<Class<?>,PacketHandler<?>>> so that you can check
if (listElement.clazz.isAssignableFrom(packet.getClass()))
handler = listElement.handler;
maybe even using priorities so that the exact class is found before a possible superclass.
I don't exactly understand what you are trying to get but you could possibly use:
if ( type.isInstance(obj) ) {
//do something
}
http://docs.oracle.com/javase/6/docs/api/java/lang/Class.html#isInstance%28java.lang.Object%29

Categories

Resources