Web Service - VRAPTOR + JSON

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.