java - Limit output payload response in CXF JAX-RS based service -


i have multiple jax-rs services built using cxf/spring. want control output payload response size of services. simplicity sake, let's none of api's in of services should ever return json response payload more 500 characters , want control in 1 place instead of relying on individual services adhere requirement. (we have other features built custom framework/base component services depend on).

i have tried implementing using jax-rs's writerinterceptor, containerresponsefilter , cxf's phase interceptor, none of approaches seem satisfy requirement. more details on i've done far:

option 1: (writerinteceptor) in overridden method, ouputstream , set max size of cache 500. when invoke api returns more 500 characters in response payload, http 400 bad request status, response body contains entire json payload.

@provider public class responsepayloadinterceptor implements writerinterceptor {     private static final logger logger = loggerfactory.getlogger(responsepayloadinterceptor.class);      @override     public void aroundwriteto(writerinterceptorcontext context) throws ioexception, webapplicationexception {         final outputstream outputstream = context.getoutputstream();          cacheandwriteoutputstream cacheandwriteoutputstream = new cacheandwriteoutputstream(outputstream);         cacheandwriteoutputstream.setmaxsize(500);         context.setoutputstream(cacheandwriteoutputstream);          context.proceed();     } } 

option 2a: (cxf phase inteceptor) in overridden method, response string ouputstream , check it's size. if it's greater 500, create new response object data too data , set in message. if response > 500 characters, http 200 ok status entire json. when use phase post_marshal or later phase, i'm able hold of json response , check it's length, time response has been streamed client.

@provider public class responsepayloadinterceptor extends abstractphaseinterceptor<message> {     private static final logger logger = loggerfactory.getlogger(responsepayloadinterceptor.class);      public responsepayloadinterceptor() {         super(phase.post_marshal);     }      @override     public void handlemessage(message message) throws fault {         logger.info("handlemessage() - response intercepted");         try {             outputstream outputstream = message.getcontent(outputstream.class); ...             cachedoutputstream cachedoutputstream = (cachedoutputstream) outputstream;             string responsebody = ioutils.tostring(cachedoutputstream.getinputstream(), "utf-8"); ...             logger.info("handlemessage() - response: {}", responsebody);             logger.info("handlemessage() - response length: {}", responsebody.length());             if (responsebody.length() > 500) {                 response response = response.status(response.status.bad_request)                                             .entity("too data").build();                 message.getexchange().put(response.class, response);             }         } catch (ioexception e) {             logger.error("handlemessage() - error");             e.printstacktrace();         }     } } 

option 2b: (cxf phase inteceptor) same above, contents of if block changed. if response length greater 500, create new output stream string too data , set in message. if response payload > 500 characters, still http 200 ok status invalid json response (entire json + additional text) i.e., response looks this: [{"data":"", ...}, {...}]too data (the text 'too data' appended json)

        if (responsebody.length() > 500) {             inputstream inputstream = new bytearrayinputstream("too data".getbytes("utf-8"));             outputstream.flush();             ioutils.copy(inputstream, outputstream);              outputstream out = new cachedoutputstream();             out.write("too data".getbytes("utf-8"));             message.setcontent(outputstream.class, out);         } 

option 3: (containerresponsefilter) using containerresponsefilter, added content-length response header value 500. if response length > 500, http 200 ok status invalid json response (truncated 500 characters). if response length < 500, still http 200 ok status, client waits more data returned server (as expected) , times out, isn't desirable solution.

@provider public class responsepayloadfilter implements containerresponsefilter {     private static final logger logger = loggerfactory.getlogger(responsepayloadfilter.class);      @override     public void filter(containerrequestcontext requestcontext, containerresponsecontext responsecontext) throws ioexception {         logger.info("filter() - response intercepted");         cachedoutputstream cos = (cachedoutputstream) responsecontext.getentitystream();         stringbuilder responsepayload = new stringbuilder();         bytearrayoutputstream out = new bytearrayoutputstream();          if (cos.getinputstream().available() > 0) {             ioutils.copy(cos.getinputstream(), out);             byte[] responseentity = out.tobytearray();             responsepayload.append(new string(responseentity));         }          logger.info("filter() - content: {}", responsepayload.tostring());         responsecontext.getheaders().add("content-length", "500");     } } 

any suggestions on how can tweak above approaches want or other different pointers?

i resolved partially using answer. partially because i'm able control payload, not response status code. ideally, if response length greater 500 , modify message content, send different response status code (other 200 ok). enough solution me proceed @ point. if figure out how update status code well, i'll come , update answer.

import org.apache.commons.io.ioutils; import org.apache.cxf.interceptor.fault; import org.apache.cxf.io.cachedoutputstream; import org.apache.cxf.message.message; import org.apache.cxf.phase.abstractphaseinterceptor; import org.apache.cxf.phase.phase; import org.slf4j.logger; import org.slf4j.loggerfactory;  import java.io.ioexception; import java.io.inputstream; import java.io.outputstream;  public class responsepayloadinterceptor extends abstractphaseinterceptor<message> {     private static final logger logger = loggerfactory.getlogger(responsepayloadinterceptor.class);      public responsepayloadinterceptor() {         super(phase.pre_stream);     }      @override     public void handlemessage(message message) throws fault {         logger.info("handlemessage() - response intercepted");         try {             outputstream outputstream = message.getcontent(outputstream.class);             cachedoutputstream cachedoutputstream = new cachedoutputstream();             message.setcontent(outputstream.class, cachedoutputstream);              message.getinterceptorchain().dointercept(message);              cachedoutputstream.flush();             cachedoutputstream.close();              cachedoutputstream newcachedoutputstream = (cachedoutputstream) message.getcontent(outputstream.class);             string currentresponse = ioutils.tostring(newcachedoutputstream.getinputstream(), "utf-8");             newcachedoutputstream.flush();             newcachedoutputstream.close();              if (currentresponse != null) {                 logger.info("handlemessage() - response: {}", currentresponse);                 logger.info("handlemessage() - response length: {}", currentresponse.length());                  if (currentresponse.length() > 500) {                     inputstream replaceinputstream = ioutils.toinputstream("{\"message\":\"too data\"}", "utf-8");                      ioutils.copy(replaceinputstream, outputstream);                     replaceinputstream.close();                      message.setcontent(outputstream.class, outputstream);                     outputstream.flush();                     outputstream.close();                 } else {                     inputstream replaceinputstream = ioutils.toinputstream(currentresponse, "utf-8");                      ioutils.copy(replaceinputstream, outputstream);                     replaceinputstream.close();                      message.setcontent(outputstream.class, outputstream);                     outputstream.flush();                     outputstream.close();                 }             }         } catch (ioexception e) {             logger.error("handlemessage() - error", e);             throw new runtimeexception(e);         }     }