Spring WebSocketStompClient:如何将STOMP消息有效负载反序列化为通用类型

时间:2019-03-31 16:17:52

标签: java stomp spring-messaging

寻找一种将STOMP消息有效负载反序列化为通用类型的最佳方法。

我有websocket服务,该服务接收实体,将其保存并向所有订阅的客户端发送消息包装的已保存实体。

在纯JSON中,它应该看起来像这样:

客户发送实体:

{
  "name": "New Facility Name"
}

我尝试在客户端处理的来自服务的消息:

{
  "type": "ADD",
  "entity": {
    "id": 123,
    "name": "New Facility Name"
  }
}

这是Java实现,无法按我期望的那样工作。

实体-具有字段Facilityid的JavaBean name

消息。

public final class UpdateMessage<T> {

    private final Type type;
    private final T entity;

    @JsonCreator
    public UpdateMessage(@JsonProperty("type") Type type, @JsonProperty("entity") T entity) {
        this.type = type;
        this.entity = entity;
    }

    // getters

    public enum Type {
        ADD,
        DELETE,
        EDIT
    }
}

测试。

@RunWith(SpringRunner.class)
@SpringBootTest
public class WebsocketClientTest {

    private CompletableFuture<UpdateMessage<Facility>> messageCompletableFuture = new CompletableFuture<>();

    @Autowired
    private WebsocketClient client;

    @Before
    public void setUp() {
        client.connect();
    }

    @After
    public void setDown() {
        client.disconnect();
    }

    @Test
    public void trySpringResolvableType() throws InterruptedException, TimeoutException, ExecutionException {
        StompSession session = client.getSession();
        session.subscribe("/topic/facility/update", new StompFrameHandler() {
            @Override
            public Type getPayloadType(StompHeaders stompHeaders) {
                return ResolvableType.forClassWithGenerics(UpdateMessage.class, Facility.class).getType();
            }

            @Override
            public void handleFrame(StompHeaders stompHeaders, Object payload) {
                //noinspection unchecked
                messageCompletableFuture.complete((UpdateMessage<Facility>) payload);
            }
        });

        Facility facility = new Facility();
        facility.setName("New Facility Name");
        client.getSession().send("/app/facility/post", facility);

        UpdateMessage<Facility> message = messageCompletableFuture.get(9, SECONDS);

        /* Get 'java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to Facility' here: */
        assertEquals(facility.getName(), message.getEntity().getName());
    }
}

“ java.lang.ClassCastException:无法将java.util.LinkedHashMap转换为Facility”的结果。

还尝试过杰克逊的TypeReference<T>

@Override
public Type getPayloadType(StompHeaders stompHeaders) {
    return new TypeReference<UpdateMessage<Facility>>() {}.getType();
}

具有相同结果和TypeFactory

@Override
public Type getPayloadType(StompHeaders stompHeaders) {
    return TypeFactory.defaultInstance().constructParametricType(UpdateMessage.class, Facility.class);
}

抛出

org.springframework.messaging.converter.MessageConversionException: Unresolvable payload type [[simple type, class UpdateMessage<Facility>]] from handler type [class FacilityController$2]

来自

org.springframework.messaging.simp.stomp.DefaultStompSession.invokeHandler(StompFrameHandler, Message<byte[]>, StompHeaders)

我设法通过包装器类使它正常工作

public final class FacilityUpdateMessage {

    private final UpdateMessage<Facility> message;

    @JsonCreator
    public FacilityUpdateMessage(@JsonProperty("type") UpdateMessage.Type type,
                                 @JsonProperty("entity") Facility entity
    ) {
        message = new UpdateMessage<>(type, entity);
    }

    public UpdateMessage<Facility> getMessage() {
        return message;
    }
}
@Override
public Type getPayloadType(StompHeaders stompHeaders) {
    return FacilityUpdateMessage.class;
}

但我不确定这是否是最佳解决方案。

0 个答案:

没有答案