简体   繁体   中英

Deserializing Java Generics with Gson

I'm writing a library for my WebSocket (STOMP) on my webserver. I'm trying to make it so that the library will return the object specified in the Generics.

Add stomp client

public <T> void addStompClient(T t, String url, String subscription, StompMessageListener<T> listener) {
    StompClient<T> sc = new StompClient<T>(t, URI.create(url));
    StompConnectionListener scl = new StompConnectionListener() {
        public void onConnecting() {}
        public void onConnected() {
            sc.subscribe(subscription, listener);
        }
        public void onDisconnected() {}
        
    };
    sc.setStompConnectionListener(scl);
    sc.connect();
    clients.add(sc);
}

StompMessageListener

@FunctionalInterface
public interface StompMessageListener<T> {

    void onMessage(T test);

}

StompClient class method and variables

@Getter
private T t;

protected StompClient(T tclass, URI serverUri) {
    super(serverUri);
    t = tclass;
}

@SuppressWarnings("unchecked")
@Override
public void onMessage(String message) {
    StompFrame stompFrame = StompFrame.fromString(message);
    
    switch (stompFrame.getCommand()) {
    case CONNECTED:
        stompConnected = true;
        if (stompConnectionListener != null) {
            stompConnectionListener.onConnected();
        }
        break;
    case MESSAGE:
        Integer subscriptionId = Integer.valueOf(stompFrame.getHeaders().get(StompHeader.SUBSCRIPTION.toString()));
        
        Class<T> tclass = (Class<T>) t.getClass();
        T test = (T) new Gson().fromJson(stompFrame.getBody(), tclass);
        
        StompSubscription<T> listener = (StompSubscription<T>) subscriptions.get(subscriptionId);
        listener.getListener().onMessage(test);
        break;
    case DISCONNECT:
        stompConnected = false;
        if (stompConnectionListener != null) {
            stompConnectionListener.onDisconnected();
        }
        break;
    default:
        break;
    }
}

Calling:

clientManager.addStompClient(Category.class, "ws://localhost:8080/stomp-api/v1/hub", "/stomp-api/v1/listener/category/create", (category) -> {
        Bukkit.getConsoleSender().sendMessage(category.getName());
    });

But in doing this, I get a:

java.lang.UnsupportedOperationException: Attempted to deserialize a java.lang.Class. Forgot to register a type adapter?

Anyone know how to fix this? I tried to add the type adapter but couldn't figure out how to do it properly

If anyone runs across this, here is how I solved this using the comment from

Alternately, you can use Jackson, which can deserialize from a Class. Here's an example. – Christopher Schneider

@Override
public void onMessage(String message) {
    StompFrame stompFrame = StompFrame.fromString(message);
    
    switch (stompFrame.getCommand()) {
    case CONNECTED:
        stompConnected = true;
        if (stompConnectionListener != null) {
            stompConnectionListener.onConnected();
        }
        break;
    case MESSAGE:
        Integer subscriptionId = Integer.valueOf(stompFrame.getHeaders().get(StompHeader.SUBSCRIPTION.toString()));
        
        ObjectMapper objectMapper = new ObjectMapper(new Gson());
        T t = objectMapper.readValue(stompFrame.getBody(), tclass);
        
        StompSubscription<T> listener = (StompSubscription<T>) subscriptions.get(subscriptionId);
        listener.getListener().onMessage(t);
        break;
    case DISCONNECT:
        stompConnected = false;
        if (stompConnectionListener != null) {
            stompConnectionListener.onDisconnected();
        }
        break;
    default:
        break;
    }
}

The ObjectMapper was put in place. tclass = Class. This allowed me to use Jackson and Generics to provide the Object that will be returning from the stomp listener

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM