Olá,
Fui solicitado aqui no trabalho a criar um web service usando JSON como forma de comunicação.
Criei um Controller com um método que aceita um parâmetro String, e então converto a String para JSON, e tudo funcionou:
Servidor:
@Post
public void sendOrder(String order) {
}
Cliente:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"></script>
<script type="text/javascript" src="https://raw.github.com/douglascrockford/JSON-js/master/json2.js"></script>
<script type="text/javascript">
$.post("orders/sendOrder",
{
order:JSON.stringify(
{"orderId":471, ... <MEU JSON ...> }
)
}
);
</script>
Se a gente olhar a requisição HTTP, os dados estarão assim:
order:{"orderId":471, ... <MEU JSON ENCODED ...> }
O problema é que o cara que está fazendo a aplicação cliente quer passar apenas o JSON, sem o nome do parâmetro no início (“order:”), como se a requisição HTTP fosse apenas:
{"orderId":471, ... <MEU JSON ...> }
Qual caminho devo seguir? Mudar o parâmetro do meu método para um objeto JSON?
Como instruir VRaptor a atribuir o conteúdo da requisição HTTP, no caso um JSON, direto para o parâmetro order?
Servidor:
@Post
public void sendOrder(JSON order) {
}
Decidi usar VRaptor por indicações de amigos, mas como não tenho muita experiência com este framework, gostaria de ouvir idéias de possíveis alternativas.
Obrigado
vc pode usar @Consumes em cima do método, daí se estiver no formato certo o VRaptor consegue converter pra um objeto:
@Consumes("application/json")
@Post
public void sendOrder(Order order) {
}
e na hora de enviar:
{"order": { "orderId": 3434, ..... } }
e o content-type application/json
Obrigado Lucas,
Tinha encontrado respostas suas sobre esse @Consumes em outras Threads mas eu estava seguindo o caminho de criar minha própria classe implementando Deserializer.
Poupou meu tempo: do jeito que você explicou, testei, funcionou.
Só precisei baixar o Jettison (http://jettison.codehaus.org/Download) e adicionar ao projeto.
Opa,
Começou a dar erro após adicionar uma lista no meu JSON, será que tenho que escrever minha própria classe para deserializar ou tem alguma forma de instruir o VRaptor a fazer isso automáticamente?
JSON:
{"order": {"orderId":471,"orderSeat":"48E","orderItems":[{"orderItem":{"quantity":1,"productId":2031}},{"orderItem":{"quantity":2,"productId":2027}}]}}
ERRO:
com.thoughtworks.xstream.converters.ConversionException: orderItem : orderItem : orderItem : orderItem
---- Debugging information ----
message : orderItem : orderItem
cause-exception : com.thoughtworks.xstream.mapper.CannotResolveClassException
cause-message : orderItem : orderItem
class : <package>.Order
required-type : [L<package>.OrderItem;
line number : -1
-------------------------------
Caused by: com.thoughtworks.xstream.mapper.CannotResolveClassException: orderItem : orderItem
Classes:
public class Order {
private int orderId;
private String orderSeat;
private List<OrderItem> orderItems;
... construtores, getters e setters
}
public class OrderItem {
private double quantity;
private int productId;
... construtores, getters e setters
}
tenta tirar o {“orderItem”: em volta dos itens
Já tinha tentado:
JSON:
{"order": {"orderId":471,"orderSeat":"48E","orderItems":[{"quantity":1,"productId":2031},{"quantity":2,"productId":2027}]}}
ERRO:
com.thoughtworks.xstream.converters.ConversionException: quantity : quantity : quantity : quantity
---- Debugging information ----
message : quantity : quantity
cause-exception : com.thoughtworks.xstream.mapper.CannotResolveClassException
cause-message : quantity : quantity
class : <package>.Order
required-type : java.util.ArrayList
line number : -1
-------------------------------
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:89)
Caused by: com.thoughtworks.xstream.mapper.CannotResolveClassException: quantity : quantity
at com.thoughtworks.xstream.mapper.DefaultMapper.realClass(DefaultMapper.java:68)
o xstream é muito ruim pra deserialização, isso pq ele usa libs diferentes pra serialização e deserialização…
tente usar o plugin do vraptor pra GSon, que é outra lib de js:
esse plugin vai ser incluído no core do vraptor na próxima versão.
basicamente é baixar esse projeto, rodar o mvn package (ou install), copiar o jar pro seu projeto e registrar o pacote: br.com.caelum.vraptor.serialization.gson
para deserialização, por enquanto copie essa classe para o seu projeto:
Obrigado mais uma vez Lucas, funcionou.
Apenas tive que reescrever também todas as minha chamadas ao método:
this.result.use(Results.json()).from( <obj> ).serialize();
Pois estava dando erro:
br.com.caelum.vraptor.InterceptionException: exception raised, check root cause for details: java.lang.NoClassDefFoundError: br/com/caelum/vraptor/serialization/xstream/Serializee
Caused by: java.lang.NoClassDefFoundError: br/com/caelum/vraptor/serialization/xstream/Serializee
Caused by: java.lang.ClassNotFoundException: br.com.caelum.vraptor.serialization.xstream.Serializee
vc está usando qual versão do VRaptor?
está funcionando agora?
Sim, está funcionando após adicionar o GSON e a classe que você indicou.
Estou usando VRaptor 3.4.0.