Problema com vraptor 4, apresenta mensagem "Method is not allowed" ao tentar adicionar um produto

Mensagem do Debug:
18:23:29,500 DEBUG [RequestHandlerObserver] Method is not allowed
br.com.caelum.vraptor.http.route.MethodNotAllowedException: Method POST is not allowed for requested URI. Allowed Methods are [GET]
at br.com.caelum.vraptor.http.route.DefaultRouter.routesMatchingUriAndMethod(DefaultRouter.java:136)
at br.com.caelum.vraptor.http.route.DefaultRouter.parse(DefaultRouter.java:111)
at br.com.caelum.vraptor.http.route.DefaultRouter$Proxy$_$$WeldClientProxy.parse(Unknown Source)
at br.com.caelum.vraptor.http.DefaultControllerTranslator.translate(DefaultControllerTranslator.java:63)
at br.com.caelum.vraptor.http.DefaultControllerTranslator$Proxy$
$$_WeldClientProxy.translate(Unknown Source)
at br.com.caelum.vraptor.observer.RequestHandlerObserver.handle(RequestHandlerObserver.java:91)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:88)
at org.jboss.weld.injection.StaticMethodInjectionPoint.invoke(StaticMethodInjectionPoint.java:78)
at org.jboss.weld.injection.MethodInvocationStrategy$SimpleMethodInvocationStrategy.invoke(MethodInvocationStrategy.java:129)
at org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:299)
at org.jboss.weld.event.ObserverMethodImpl.sendEvent(ObserverMethodImpl.java:277)
at org.jboss.weld.event.ObserverMethodImpl.notify(ObserverMethodImpl.java:255)
at org.jboss.weld.event.ObserverNotifier.notifySyncObservers(ObserverNotifier.java:269)
at org.jboss.weld.event.ObserverNotifier.notify(ObserverNotifier.java:258)
at org.jboss.weld.event.EventImpl.fire(EventImpl.java:91)
at br.com.caelum.vraptor.VRaptor.doFilter(VRaptor.java:123)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:94)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:496)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:502)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1156)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1539)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1495)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
at java.lang.Thread.run(Unknown Source)

Arquivo .JS
$(function () {
$("#btn-submit-insert").click(function (){
productInsert();
});
});

function productInsert(){
	var name = $('#name').val();	
	var price = $('#price').val();
	var description = $('#description').val();

	var product = {
		'product': {
			'name': name,
			'price': price,
			'description': description
		}
	};
	console.log(product);

	$.ajax({
		url:'http://localhost:8080/challenge/product/save',
		contentType: 'application/json',
		type:'GET',
		data: JSON.parse(product),
		success: console.log("sucesso")
	});
}

JSP:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script
	src="${pageContext.request.contextPath}/js/jquery-ui-1.12.1.custom/external/jquery/jquery.js"></script>
<script
	src="${pageContext.request.contextPath}/js/jquery-ui-1.12.1.custom/jquery-ui.min.js"></script>
<script src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
<link type="text/css" rel="stylesheet"
	href="${pageContext.request.contextPath}/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet"
	href="${pageContext.request.contextPath}/css/bootstrap-grid.min.css" />
<link type="text/css" rel="stylesheet"
	href="${pageContext.request.contextPath}/css/stylesheet.css" />
<script src="${pageContext.request.contextPath}/js/insert.js"></script>
<title>Products</title>
</head>
<div class="container">
	<div class="row">
		<div role="main">
			<h2>Adicionar Produto</h2>
			<form method="POST">
				<div class="form-group row">
					<input class="form-control" type="text" id="name"
						name="product.name" required="true" placeholder="Nome do Produto" />
				</div>
				<div class="form-group row">

					<input class="form-control" type="text" id="price"
						name="product.price" required="true" placeholder="Informe o preço" />
				</div>
				<div class="form-group row">
					<textarea class="form-control" rows="5" type="text"
						id="description" name="product.description"
						placeholder="Descrição do produto" /></textarea>
				</div>
				<input class="btn btn-primary" id="btn-submit-insert" type="submit" value="Salvar" />
			</form>
		</div>
	</div>
</div>
</body>
</html>

Controller:

	@Post
	@Consumes(value="application/json", options=WithoutRoot.class)
	@Path("/product/save")
	public void save(Product product) {
		this.productDao.startTransaction();
		this.productDao.save(product);
		result.use(Results.json()).withoutRoot().from(product).serialize();
		this.productDao.commitTransaction();
	}

Troca @post por @get no metodo save

Nao sou especialista em vraptor, mas tem certeza que você pode usar essas anotaçoes @Post e @Path assim?
Pela documentaçao parece que você deveria ter:

@Post("/product/save")

E pra mim é confuso a mensagem já que no seu ajax, você tá enviando com método ‘get’ onde deveria ser ‘post’

É preciso ter cuidado quando usar GET e POST assim. Muitas pessoas e ferramentas assumem que GET é um método seguro pra ser chamado múltiplas vezes e que nao muda nada quando você accessa uma URL com get.

Se colocar na web um site que salva usando GET, pode correr o risco de ter vários items salvos quando o google for indexar seu site, por exemplo.

Fala @AbelBueno, @Mefistofoles66 tranquilo? para que uma requisição possa disparar um método no vraptor e necessário existir a mesma combinação Verbo HTTP + URL na configuração do método desejado, por exemplo no trecho:

@Post
@Consumes(value="application/json", options=WithoutRoot.class)
@Path("/product/save")
public void save(Product product) {
	this.productDao.startTransaction();
this.productDao.save(product);
	result.use(Results.json()).withoutRoot().from(product).serialize();
	this.productDao.commitTransaction();
}

está dizendo que para ser disparado a requisição deve ser do tipo Post na URL:/product/save como a requisição está vindo do tipo GET na URL /product/save o vraptor reclama.

Existe um padrão (que não e lei) de uso dos verbos HTTP por ex:

  • GET quando vou fazer consultas, obtenção de dados
  • POST quando vou submeter formulários
  • PUT para atualizar dados
  • DELETE para remover dados

Oi @cassunde,

Pois é, essa foi minha primeira impressao vendo o código, mas a mensagem de erro aponta o cenário contrário:

18:23:29,500 DEBUG [RequestHandlerObserver] Method is not allowed
br.com.caelum.vraptor.http.route.MethodNotAllowedException: Method POST is not allowed for requested URI. Allowed Methods are [GET]

Pelo que entendo aqui está dizendo que foi feito um POST nessa URI mas ela só aceita GET, que é o comportamento contrário do que se espera vendo o código.

Boa Tarde @cassunde, @AbelBueno meu problema é o seguinte, na JSP insert recebo este form.

JSP:

<%@page contentType="text/html" pageEncoding="UTF-8"%>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%>
<!DOCTYPE html">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<script
	src="${pageContext.request.contextPath}/js/jquery-ui-1.12.1.custom/external/jquery/jquery.js"></script>
<script
	src="${pageContext.request.contextPath}/js/jquery-ui-1.12.1.custom/jquery-ui.min.js"></script>
<script src="${pageContext.request.contextPath}/js/bootstrap.min.js"></script>
<link type="text/css" rel="stylesheet"
	href="${pageContext.request.contextPath}/css/bootstrap.min.css" />
<link type="text/css" rel="stylesheet"
	href="${pageContext.request.contextPath}/css/bootstrap-grid.min.css" />
<link type="text/css" rel="stylesheet"
	href="${pageContext.request.contextPath}/css/stylesheet.css" />
<script src="${pageContext.request.contextPath}/js/insert.js"></script>
<title>Products</title>
</head>
<div class="container">
	<div class="row">
		<div role="main">
			<h2>Adicionar Produto</h2>
			<form method="POST">
				<div class="form-group row">
					<input class="form-control" type="text" id="name"
						name="product.name" required="true" placeholder="Nome do Produto" />
				</div>
				<div class="form-group row">

					<input class="form-control" type="text" id="price"
						name="product.price" required="true" placeholder="Informe o preço" />
				</div>
				<div class="form-group row">
					<textarea class="form-control" rows="5" type="text"
						id="description" name="product.description"
						placeholder="Descrição do produto" /></textarea>
				</div>
				<input class="btn btn-primary" id="btn-submit-insert" type="submit" value="Salvar" />
			</form>
		</div>
	</div>
</div>
</body>
</html>

tenho em meu ProductController o metodo:

	@Get("/product")
	public void insert() {

	}

que direciona para o jsp, e quero recuperar as informações deste form com

@Consumes(value="application/json", options=WithoutRoot.class)
	@Post("/product/save")
	public void save(Product product) {
		this.productDao.startTransaction();
		this.productDao.save(product);
		result.use(Results.json()).withoutRoot().from(product).serialize();
		this.productDao.commitTransaction();
	}

Anteriormente eu fazia isso com

${linkTo[ProductController].save}

mas quero receber e persistir esses dados via json.

O método do form esta como POST

lembrando que

pelo que me parece o que vc precisa e trocar esse @get pelo @Post nesse método:

o seu form esta mandando um POST mas a url que está configurando no submit está recebendo um @GET no controller do vRaptor