2016-06-11 2 views
3

Если я использую Resteasy, я могу использовать Resteasy-ДЖЕКСОН-провайдер, который обрабатывает сортировочным свои объекты в JSON и обратно для моих остальных конечных точек, например:Generic кодеры и декодеры с Jetty WebSockets

@GET 
@Path("/") 
@Produces({MediaType.APPLICATION_JSON}) 
public MyThing getSingle() { 
    return new MyThing(); 
} 

Это хорошо, поскольку это означает, что мне не нужно указывать кодировщик для каждого типа - Джексон просто справляется с этим.

Я сейчас обучения WebSockets, и я считаю, что я должен предоставить кодеры:

@ServerEndpoint(value = "/websocket", encoders = {MyThingEncoder.class}, decoders = {MyThingDecoder.class}) 
public class Websocket { 

    @OnOpen 
    public void onOpen(Session session) { 
      session.getBasicRemote().sendObject(new MyThing()); 
    } 
} 

Это расстраивает, так как я не хочу, чтобы обеспечить кодер/декодер для каждого отдельного типа объекта , особенно если они просто используют Джексона. Прямо сейчас, мои кодер/декодеры выглядеть следующим образом:

public class MyThingEncoder implements Encoder.Text<MyThing> { 

    private static final ObjectMapper MAPPER = new ObjectMapper(); 

    @Override 
    public void init(EndpointConfig endpointConfig) { 
    } 

    @Override 
    public void destroy() { 
    } 

    @Override 
    public String encode(MyThing t) throws EncodeException { 
     try { 
      return MAPPER.writeValueAsString(t); 
     } catch (IOException e) { 
      throw new EncodeException(t, "Could not encode.", e); 
     } 
    } 
} 

Я попытался с помощью дженериков, изменив определение класса на MyThingEncoder (ниже), но он бросил исключение (и ниже):

package com.jetnuts.serv.encoders; 

import org.codehaus.jackson.map.ObjectMapper; 
import org.jboss.resteasy.util.Encode; 

import javax.websocket.*; 
import java.io.IOException; 

public class MyThingEncoder<T> implements Encoder.Text<T> { 

    private static final ObjectMapper MAPPER = new ObjectMapper(); 

    Class<T> typeOf; 

    @Override 
    public void init(EndpointConfig endpointConfig) { 
    } 

    @Override 
    public void destroy() { 
    } 

    @Override 
    public String encode(T t) throws EncodeException { 
     try { 
      return MAPPER.writeValueAsString(t); 
     } catch (IOException e) { 
      throw new EncodeException(t, "Could not encode.", e); 
     } 
    } 
} 

исключение:

org.eclipse.jetty.websocket.api.InvalidWebSocketException: Invalid type declared for interface javax.websocket.Encoder$Text on class class com.jetnuts.serv.encoders.MyThingEncoder 
    at org.eclipse.jetty.websocket.jsr356.metadata.EncoderMetadataSet.getEncoderType(EncoderMetadataSet.java:82) 
    at org.eclipse.jetty.websocket.jsr356.metadata.EncoderMetadataSet.discover(EncoderMetadataSet.java:50) 
    at org.eclipse.jetty.websocket.jsr356.metadata.CoderMetadataSet.addAll(CoderMetadataSet.java:78) 
    at org.eclipse.jetty.websocket.jsr356.server.AnnotatedServerEndpointMetadata.<init>(AnnotatedServerEndpointMetadata.java:51) 
    at org.eclipse.jetty.websocket.jsr356.server.ServerContainer.getServerEndpointMetadata(ServerContainer.java:162) 
    at org.eclipse.jetty.websocket.jsr356.server.ServerContainer.addEndpoint(ServerContainer.java:87) 
    at org.eclipse.jetty.websocket.jsr356.server.ServerContainer.doStart(ServerContainer.java:139) 
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.start(ContainerLifeCycle.java:132) 
    at org.eclipse.jetty.util.component.ContainerLifeCycle.doStart(ContainerLifeCycle.java:106) 
    at org.eclipse.jetty.server.handler.AbstractHandler.doStart(AbstractHandler.java:61) 
    at org.eclipse.jetty.server.handler.ScopedHandler.doStart(ScopedHandler.java:120) 
    at org.eclipse.jetty.server.handler.ContextHandler.startContext(ContextHandler.java:803) 
    at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:344) 
    at org.eclipse.jetty.webapp.WebAppContext.startWebapp(WebAppContext.java:1379) 
    at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1341) 
    at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:772) 
    at org.eclipse.jetty.servlet.ServletContextHandler.doStart(ServletContextHandler.java:261) 
    at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:517) 
    at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:68) 
    at org.eclipse.jetty.deploy.bindings.StandardStarter.processBinding(StandardStarter.java:41) 
    at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:188) 
    at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:499) 
    at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:147) 
    at org.eclipse.jetty.deploy.providers.ScanningAppProvider.fileAdded(ScanningAppProvider.java:180) 
    at org.eclipse.jetty.deploy.providers.WebAppProvider.fileAdded(WebAppProvider.java:458) 
    at org.eclipse.jetty.deploy.providers.ScanningAppProvider$1.fileAdded(ScanningAppProvider.java:64) 
    at org.eclipse.jetty.util.Scanner.reportAddition(Scanner.java:610) 
    at org.eclipse.jetty.util.Scanner.reportDifferences(Scanner.java:529) 
    at org.eclipse.jetty.util.Scanner.scan(Scanner.java:392) 
    at org.eclipse.jetty.util.Scanner$1.run(Scanner.java:329) 
    at java.util.TimerThread.mainLoop(Timer.java:555) 
    at java.util.TimerThread.run(Timer.java:505) 

Как я могу избежать необходимости кодера/декодера, который делает ту же самую вещь для каждого типа объекта, я хочу отправить/получить?

+0

Я нашел, что я могу просто использовать «объект» для кодера, но для декодера мне еще нужно указать тип. – ThePerson

ответ

3
import com.fasterxml.jackson.core.type.TypeReference; 
import com.fasterxml.jackson.databind.ObjectMapper; 

import javax.websocket.DecodeException; 
import javax.websocket.Decoder; 
import javax.websocket.EndpointConfig; 
import java.io.IOException; 
import java.io.Reader; 

public class DataDecoder implements Decoder.TextStream<Object> { 

@Override 
public Object decode(Reader reader) throws DecodeException, IOException { 

    ObjectMapper mapper = new ObjectMapper(); 
    return mapper.readValue(reader, new TypeReference<Object>() { 
    }); 

} 

@Override 
public void init(EndpointConfig config) { 

} 

@Override 
public void destroy() { 

} 
} 



@ClientEndpoint (decoders = { DataDecoder.class }) 
public class SomeClass { 


private WebSocketContainer container; 

private Session session; 
private Object objectModel; 

@Override 
public SomeType getAimedJobs() throws DatabaseException, ModuleNotLoadException, NamingException { 



    SomeType someType = new SomeType(); 
    ObjectMapper mapper = new ObjectMapper(); 
    try { 
     String jsonInString = mapper.writeValueAsString(this.objectModel); 
     someType = mapper.readValue(jsonInString, SomeType.class); 
    } catch (IOException e) { 
     e.printStackTrace(); 
    } 
    return someType ; 
} 


@OnOpen 
public void onOpen(Session session) { 

    this.session = session; 
} 

@OnMessage 
public void onMessage(Object o) { 

    this.objectModel = o; 
} 

@OnClose 
public void onClose(CloseReason reason) { 

    System.out.println("WebSocket connection closed with CloseCode: " + reason.getCloseCode()); 
    this.session.Close(); 
} 

}

+0

Пожалуйста, объясните свой ответ. – Fidel90

+1

как @ThePerson сказал, что для обработчика обработанного объекта я тоже использую объект в декодере, таким образом я использую тип объекта в Decoder.TextStream , поэтому с использованием нового jackson api, обратите внимание, что objectmapper находится в привязке данных не к основному модулю, readvalue метод, который получает два параметра .one java.io.reader, который строит объектный считыватель и typereference, которые получают тип объекта. на самом деле, когда u вызывается метод sendobject() в стороне сервера, тогда декодер запускается, и ваш пользовательский объект изменяется на тип объекта декодером до вызова метода onmessage на стороне клиента. на стороне клиента, я имею в виду SomeClass, –

+0

в методе onmessage, я устанавливаю поле objectmodel, а затем я могу использовать его в любом методе, поэтому теперь в objectmodel существует объект, который для этой цели должен быть преобразован в мой пользовательский тип. Я снова использую jackson api first objectmodel convert в строку с методом mapper.writeValueAsString(), затем преобразуйте в пользовательский тип с mapper.readValue(). –

Смежные вопросы