有没有办法在 Wildfly 中禁用自动 JSON PATCH 应用程序
Is there a way to disable automatic JSON PATCH application in Wildfly
在 Wildfly 上使用 JAX-RS 中的 HTTP-PATCH
资源时(使用 14 和 18 进行测试),会发生一些使用 GET
调用相同资源路径的自动操作,应用来自 JSON-PATCH 并用结果调用实际方法。
$ curl localhost:8080/so/auto/Bob -H 'Content-Type: application/json-patch+json' -X PATCH -d '[{"op":"replace","path":"/age","value":24}]' -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> PATCH /so/auto/Bob HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Type: application/json-patch+json
> Content-Length: 43
>
* upload completely sent off: 43 out of 43 bytes
< HTTP/1.1 200 OK
< Connection: keep-alive
< Transfer-Encoding: chunked
< Content-Type: application/json
< Date: Tue, 26 Nov 2019 12:45:51 GMT
<
* Connection #0 to host localhost left intact
{"age":24,"name":"Bob"}
有没有办法禁用此行为(使 #patchManual
工作)?
$ curl localhost:8080/so/manual/Bob -H 'Content-Type: application/json-patch+json' -X PATCH -d '[{"op":"replace","path":"/age","value":24}]' -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> PATCH /so/manual/Bob HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Type: application/json-patch+json
> Content-Length: 43
>
* upload completely sent off: 43 out of 43 bytes
< HTTP/1.1 400 Bad Request
< Connection: keep-alive
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 41
< Date: Tue, 26 Nov 2019 12:42:58 GMT
<
* Connection #0 to host localhost left intact
not a json patch: {"name":"Bob","age":24}
重现问题的代码:
package so;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonPatch;
import javax.json.JsonStructure;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PATCH;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
@Path( "/" )
public class MyPatchResource
{
public static class Data
{
public String name;
public int age;
}
@GET
@Produces( MediaType.APPLICATION_JSON )
@Path( "auto/{name}" )
public Data read( @PathParam( "name" ) String name )
{
Data result = new Data();
result.name = name;
result.age = 42;
return result;
}
@PATCH
@Path( "auto/{name}" )
@Consumes( MediaType.APPLICATION_JSON_PATCH_JSON )
@Produces( MediaType.APPLICATION_JSON )
public Data patchAuto( Data patched )
{
return patched;
}
@PATCH
@Path( "manual/{name}" )
@Consumes( MediaType.APPLICATION_JSON_PATCH_JSON )
@Produces( MediaType.APPLICATION_JSON )
public JsonObject patchManual( @PathParam( "name" ) String name, JsonStructure patch )
{
if ( !(patch instanceof JsonArray) )
{
throw new WebApplicationException( Response.status( Status.BAD_REQUEST )
.type( MediaType.TEXT_PLAIN )
.entity( "not a json patch: " + patch )
.build() );
}
JsonPatch jsonPatch = Json.createPatch( patch.asJsonArray() );
JsonObject original = readManual( name );
return jsonPatch.apply( original );
}
@GET
@Path( "manual/{name}" )
@Produces( MediaType.APPLICATION_JSON )
public JsonObject readManual( @PathParam( "name" ) String name )
{
return Json.createObjectBuilder()
.add( "name", name )
.add( "age", 42 )
.build();
}
}
所以我找到了解决办法...
1) 定义自定义 http 方法
@Target( { ElementType.METHOD } )
@Retention( RetentionPolicy.RUNTIME )
@HttpMethod( "JSONPATCH" )
@Documented
public @interface JSONPATCH
{}
2) 使用业务资源中的方法
- @PATCH
+ @JSONPATCH
@Path( "manual/{name}" )
@Consumes( MediaType.APPLICATION_JSON_PATCH_JSON )
@Produces( MediaType.APPLICATION_JSON )
public JsonObject patchManual( @PathParam( "name" ) String name, JsonStructure patch )
3) 创建一个预匹配的 ContainerRequestFilter,将 PATCH 请求移动到 JSONPATCH
@Provider
@PreMatching
public class JsonPatchEnableFilter implements ContainerRequestFilter
{
@Override
public void filter( ContainerRequestContext ctx ) throws IOException
{
if ( ctx.getMethod().equals( HttpMethod.PATCH )
&& MediaType.APPLICATION_JSON_PATCH_JSON_TYPE.isCompatible( ctx.getMediaType() ) )
{
ctx.setMethod( "JSONPATCH" );
}
}
}
这通过绕过过滤器完全禁用了原始行为,这可能可以通过向过滤器添加额外的逻辑来调整。
在 Wildfly 上使用 JAX-RS 中的 HTTP-PATCH
资源时(使用 14 和 18 进行测试),会发生一些使用 GET
调用相同资源路径的自动操作,应用来自 JSON-PATCH 并用结果调用实际方法。
$ curl localhost:8080/so/auto/Bob -H 'Content-Type: application/json-patch+json' -X PATCH -d '[{"op":"replace","path":"/age","value":24}]' -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> PATCH /so/auto/Bob HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Type: application/json-patch+json
> Content-Length: 43
>
* upload completely sent off: 43 out of 43 bytes
< HTTP/1.1 200 OK
< Connection: keep-alive
< Transfer-Encoding: chunked
< Content-Type: application/json
< Date: Tue, 26 Nov 2019 12:45:51 GMT
<
* Connection #0 to host localhost left intact
{"age":24,"name":"Bob"}
有没有办法禁用此行为(使 #patchManual
工作)?
$ curl localhost:8080/so/manual/Bob -H 'Content-Type: application/json-patch+json' -X PATCH -d '[{"op":"replace","path":"/age","value":24}]' -v
* Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 8080 (#0)
> PATCH /so/manual/Bob HTTP/1.1
> Host: localhost:8080
> User-Agent: curl/7.64.1
> Accept: */*
> Content-Type: application/json-patch+json
> Content-Length: 43
>
* upload completely sent off: 43 out of 43 bytes
< HTTP/1.1 400 Bad Request
< Connection: keep-alive
< Content-Type: text/plain;charset=UTF-8
< Content-Length: 41
< Date: Tue, 26 Nov 2019 12:42:58 GMT
<
* Connection #0 to host localhost left intact
not a json patch: {"name":"Bob","age":24}
重现问题的代码:
package so;
import javax.json.Json;
import javax.json.JsonArray;
import javax.json.JsonObject;
import javax.json.JsonPatch;
import javax.json.JsonStructure;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.PATCH;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.Status;
@Path( "/" )
public class MyPatchResource
{
public static class Data
{
public String name;
public int age;
}
@GET
@Produces( MediaType.APPLICATION_JSON )
@Path( "auto/{name}" )
public Data read( @PathParam( "name" ) String name )
{
Data result = new Data();
result.name = name;
result.age = 42;
return result;
}
@PATCH
@Path( "auto/{name}" )
@Consumes( MediaType.APPLICATION_JSON_PATCH_JSON )
@Produces( MediaType.APPLICATION_JSON )
public Data patchAuto( Data patched )
{
return patched;
}
@PATCH
@Path( "manual/{name}" )
@Consumes( MediaType.APPLICATION_JSON_PATCH_JSON )
@Produces( MediaType.APPLICATION_JSON )
public JsonObject patchManual( @PathParam( "name" ) String name, JsonStructure patch )
{
if ( !(patch instanceof JsonArray) )
{
throw new WebApplicationException( Response.status( Status.BAD_REQUEST )
.type( MediaType.TEXT_PLAIN )
.entity( "not a json patch: " + patch )
.build() );
}
JsonPatch jsonPatch = Json.createPatch( patch.asJsonArray() );
JsonObject original = readManual( name );
return jsonPatch.apply( original );
}
@GET
@Path( "manual/{name}" )
@Produces( MediaType.APPLICATION_JSON )
public JsonObject readManual( @PathParam( "name" ) String name )
{
return Json.createObjectBuilder()
.add( "name", name )
.add( "age", 42 )
.build();
}
}
所以我找到了解决办法...
1) 定义自定义 http 方法
@Target( { ElementType.METHOD } )
@Retention( RetentionPolicy.RUNTIME )
@HttpMethod( "JSONPATCH" )
@Documented
public @interface JSONPATCH
{}
2) 使用业务资源中的方法
- @PATCH
+ @JSONPATCH
@Path( "manual/{name}" )
@Consumes( MediaType.APPLICATION_JSON_PATCH_JSON )
@Produces( MediaType.APPLICATION_JSON )
public JsonObject patchManual( @PathParam( "name" ) String name, JsonStructure patch )
3) 创建一个预匹配的 ContainerRequestFilter,将 PATCH 请求移动到 JSONPATCH
@Provider
@PreMatching
public class JsonPatchEnableFilter implements ContainerRequestFilter
{
@Override
public void filter( ContainerRequestContext ctx ) throws IOException
{
if ( ctx.getMethod().equals( HttpMethod.PATCH )
&& MediaType.APPLICATION_JSON_PATCH_JSON_TYPE.isCompatible( ctx.getMediaType() ) )
{
ctx.setMethod( "JSONPATCH" );
}
}
}
这通过绕过过滤器完全禁用了原始行为,这可能可以通过向过滤器添加额外的逻辑来调整。