Desserializando JSON com base no tipo de objeto

Estou criando um serviço que recebe solicitações na forma de mensagens JSON. Preciso analisar a mensagem e executar a ação apropriada com base no tipo de solicitação. Por exemplo (no pseudo código):

switch(request.type) {
    case "NewOrder":
        createNewOrder(order);
        break;
    case "CancelOrder"
        cancelOrder(orderId);
        break;
}

Parece que a maioria das APIs JSON (pelo menos aquelas que fazem o mapeamento de objetos para você) precisam do tipo de objeto raiz para desserializar. Existe alguma maneira elegante de contornar isso?

Como exemplo, na API de Jackson (usando o mapeamento completo de objetos), preciso chamar o mapeador da seguinte maneira:

NewOrder newOrder = mapper.readValue(src, NewOrder.class);
CancelOrder cancelOrder = mapper.readValue(src. CancelOrder.class);

O que significa que eu preciso conhecer a classe do objeto antes mesmo de analisá-lo. O que eu realmente preciso é de uma maneira de espiar a string JSON, determinar o tipo de solicitação e chamar o método readValue () apropriado - algo como isto:

String requestType = getRequestType(src);
switch(request.type) {
    case "NewOrder":
        NewOrder newOrder = mapper.readValue(src, NewOrder.class);
        createNewOrder(newOrder.order);
        break;
    case "CancelOrder"
        CancelOrder cancelOrder = mapper.readValue(src. CancelOrder.class);
        cancelOrder(cancelOrder.orderId);
        break;
}

É possível fazer isso usando Jackson ou qualquer outro analisador Java JSON? Tenho certeza de que posso ir para um nível mais baixo e usar uma API de streaming ou uma API baseada em nó, mas tentando evitar essa complexidade, se puder.

Resposta 1

Se você usar Jackson para analisar a entrada JSON em um Mapa, poderá acessar rapidamente as informações de tipo. Você pode criar o objeto como a classe necessária e usá-lo ObjectMapper.convertpara configurar o objeto no Mapa que você obteve de Jackson.

Aqui está um exemplo:

public class Test1 {
private String f;
private String b;

public void setFoo(String v) { f = v; }

public void setBim(String v) { b = v; }

public String toString() { return "f=" + f + ", b=" + b; }


public static void main(String[] args) throws Exception {
    String test = "{ \"foo\":\"bar\", \"bim\":\"baz\" }";
    ObjectMapper mapper = new ObjectMapper();
    HashMap map = mapper.readValue(new StringReader(test), HashMap.class);
    System.out.println(map);
    Test1 test1 = mapper.convertValue(map, Test1.class);
    System.out.println(test1);
}
}
Resposta: 2

Você pode usar um invólucro em torno de seu pedido:

{
"NewOrder": {...}
}

ou

{
"CancelOrder": {...}
}

ATUALIZAR:

class Wrapper {
    newOrder: NewOrder;
    cancelOrderId: Integer;
}

Wrapper wrapper = mapper.readValue(src, Wrapper.class);

if (wrapper.newOrder != null) {
    createNewOrder(wrapper.newOrder);
}
if (wrapper.cancelOrderId != null) {
    cancelOrder(wrapper.cancelOrderId);
}
Resposta: 3

Supondo que o pedido seja apenas dados, delegar responsabilidade a um DoSomethingService e produzir o serviço através de uma fábrica pode ajudar:

Service service = takeActionFactory
    .buildTheRightServiceForTheValue(src);
service.takeAction();

A fábrica analisaria o objeto JSON:

Service buildTheRightServiceForTheValue(src) {
    switch(request.type) {
    case "NewOrder":
        return new NewOrderService(mapper.readValue(src, NewOrder.class)); 
        break;
    case "CancelOrder"
        return new CancelOrderService(mapper.readValue(src. CancelOrder.class));
        break;
    }
    case "SomeOtherObject"
        return new SomeOtherService(mapper.readValue(src, SomeOtherService.class));
    }

E os serviços concretos são subclasses de Serviço:

NewOrderService implements Service {
    private final NewOrder newOrder;
    /**constructor*/
    ...

    void takeAction() {
        createNewOrder(newOrder.order);
    }
}
Resposta: 4

Estou tentando criar um soapMessage para passar posteriormente para o seguinte trecho de código: SOAPConnectionFactory soapConnectionFactory = SOAPConnectionFactory.newInstance (); Conexão SOAPConnection = ...

Estou pensando em criar um jogo 2D em Java e tive um problema com animação: como faço para interpolar em Java? Existem bibliotecas ou algo para o qual eu possa encontrar ligações? Além disso, por favor ...

Se eu tiver algo parecido abaixo, então o que isso significa dentro do bloco sincronizado sincronizado (syncObject) {Basicamente, isso significa que apenas um segmento pode estar dentro do bloco acima e assim que um ...

Como executo um aplicativo externo, transmito os argumentos e retorno o resultado do aplicativo externo usando java #ProcessBuilder e #RunTime? teste de classe pública {public static void main (...