Merged searchapi (5.2.1) to 5.2.N (5.2.1)

129777 gjames: Reformatted to Alfresco standards


git-svn-id: https://svn.alfresco.com/repos/alfresco-enterprise/alfresco/BRANCHES/DEV/5.2.N/root@130168 c4b6b30b-aa2e-2d43-bbcb-ca4b014f7261
This commit is contained in:
Gethin James
2016-09-06 14:14:52 +00:00
parent b2a6ad44ef
commit f60bdb5914
3 changed files with 104 additions and 99 deletions

View File

@@ -23,6 +23,7 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.rest.framework.tools; package org.alfresco.rest.framework.tools;
import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException; import org.alfresco.rest.framework.core.exceptions.InvalidArgumentException;
@@ -74,16 +75,18 @@ public interface RecognizedParamsExtractor
public static final String PARAM_SELECT = "select"; public static final String PARAM_SELECT = "select";
public static final String PARAM_INCLUDE = "include"; public static final String PARAM_INCLUDE = "include";
public static final String PARAM_INCLUDE_SOURCE_ENTITY = "includeSource"; public static final String PARAM_INCLUDE_SOURCE_ENTITY = "includeSource";
public static final List<String> KNOWN_PARAMS = Arrays.asList( public static final List<String> KNOWN_PARAMS = Arrays
PARAM_RELATIONS, PARAM_FILTER_PROPERTIES, PARAM_FILTER_FIELDS,PARAM_PAGING_SKIP,PARAM_PAGING_MAX, .asList(PARAM_RELATIONS, PARAM_FILTER_PROPERTIES, PARAM_FILTER_FIELDS, PARAM_PAGING_SKIP, PARAM_PAGING_MAX, PARAM_ORDERBY,
PARAM_ORDERBY, PARAM_WHERE, PARAM_SELECT, PARAM_INCLUDE_SOURCE_ENTITY); PARAM_WHERE, PARAM_SELECT, PARAM_INCLUDE_SOURCE_ENTITY);
default Log rpeLogger() { default Log rpeLogger()
{
return LogFactory.getLog(this.getClass()); return LogFactory.getLog(this.getClass());
} }
/** /**
* Finds the formal set of params that any rest service could potentially have passed in as request params * Finds the formal set of params that any rest service could potentially have passed in as request params
*
* @param req WebScriptRequest * @param req WebScriptRequest
* @return RecognizedParams a POJO containing the params for use with the Params objects * @return RecognizedParams a POJO containing the params for use with the Params objects
*/ */
@@ -112,39 +115,28 @@ public interface RecognizedParamsExtractor
BeanPropertiesFilter filter = getFilter((fields != null ? fields : properties), includedFields); BeanPropertiesFilter filter = getFilter((fields != null ? fields : properties), includedFields);
return new Params.RecognizedParams(requestParams, paging, filter, relationFilter, includedFields, selectFields, whereQuery, sorting, includeSource); return new Params.RecognizedParams(requestParams, paging, filter, relationFilter, includedFields, selectFields, whereQuery, sorting,
includeSource);
} }
/** /**
* Takes the web request and looks for a "fields" parameter (otherwise deprecated "properties" parameter). * Takes the web request and looks for a "fields" parameter (otherwise deprecated "properties" parameter).
*
* Parses the parameter and produces a list of bean properties to use as a filter A * Parses the parameter and produces a list of bean properties to use as a filter A
* SimpleBeanPropertyFilter it returned that uses the bean properties. If no * SimpleBeanPropertyFilter it returned that uses the bean properties. If no
* filter param is set then a default BeanFilter is returned that will never * filter param is set then a default BeanFilter is returned that will never
* filter fields (ie. Returns all bean properties). * filter fields (ie. Returns all bean properties).
*
* If selectList is provided then it will take precedence (ie. be included) over the fields/properties filter * If selectList is provided then it will take precedence (ie. be included) over the fields/properties filter
* for top-level entries (bean properties). * for top-level entries (bean properties).
*
* For example, this will return entries from both select & properties, eg. * For example, this will return entries from both select & properties, eg.
* * select=abc,def&properties=id,name,ghi
* select=abc,def&properties=id,name,ghi
*
* Note: it should be noted that API-generic "fields" clause does not currently work for sub-entries. * Note: it should be noted that API-generic "fields" clause does not currently work for sub-entries.
*
* Hence, even if the API-specific "select" clause allows selection of a sub-entries this cannot be used * Hence, even if the API-specific "select" clause allows selection of a sub-entries this cannot be used
* with "fields" filtering. For example, an API-specific method may implement and return "abc/blah", eg. * with "fields" filtering. For example, an API-specific method may implement and return "abc/blah", eg.
* * select=abc/blah
* select=abc/blah
*
* However the following will not return "abc/blah" if used with fields filtering, eg. * However the following will not return "abc/blah" if used with fields filtering, eg.
* * select=abc/blah&fields=id,name,ghi
* select=abc/blah&fields=id,name,ghi
*
* If fields filtering is desired then it would require "abc" to be selected and returned as a whole, eg. * If fields filtering is desired then it would require "abc" to be selected and returned as a whole, eg.
* * select=abc&fields=id,name,ghi
* select=abc&fields=id,name,ghi
* *
* @param filterParams * @param filterParams
* @param selectList * @param selectList
@@ -178,9 +170,9 @@ public interface RecognizedParamsExtractor
return BeanPropertiesFilter.ALLOW_ALL; return BeanPropertiesFilter.ALLOW_ALL;
} }
/** /**
* Takes the "select" parameter and turns it into a List<String> property names * Takes the "select" parameter and turns it into a List<String> property names
*
* @param selectParam String * @param selectParam String
* @return bean property names potentially using JSON Pointer syntax * @return bean property names potentially using JSON Pointer syntax
*/ */
@@ -193,6 +185,7 @@ public interface RecognizedParamsExtractor
/** /**
* Takes the "include" parameter and turns it into a List<String> property names * Takes the "include" parameter and turns it into a List<String> property names
*
* @param includeParam String * @param includeParam String
* @return bean property names potentially using JSON Pointer syntax * @return bean property names potentially using JSON Pointer syntax
*/ */
@@ -204,44 +197,48 @@ public interface RecognizedParamsExtractor
/** /**
* Gets the clause specificed in paramName * Gets the clause specificed in paramName
*
* @param param * @param param
* @param paramName * @param paramName
* @return bean property names potentially using JSON Pointer syntax * @return bean property names potentially using JSON Pointer syntax
*/ */
default List<String> getClause(String param, String paramName) default List<String> getClause(String param, String paramName)
{ {
if (param == null) return Collections.emptyList(); if (param == null)
return Collections.emptyList();
try { try
CommonTree selectedPropsTree = WhereCompiler.compileSelectClause(param); {
if (selectedPropsTree instanceof CommonErrorNode) CommonTree selectedPropsTree = WhereCompiler.compileSelectClause(param);
{ if (selectedPropsTree instanceof CommonErrorNode)
rpeLogger().debug("Error parsing the "+paramName+" clause "+selectedPropsTree); {
throw new InvalidSelectException(paramName, selectedPropsTree); rpeLogger().debug("Error parsing the " + paramName + " clause " + selectedPropsTree);
} throw new InvalidSelectException(paramName, selectedPropsTree);
if (selectedPropsTree.getChildCount() == 0 && !selectedPropsTree.getText().isEmpty()) }
{ if (selectedPropsTree.getChildCount() == 0 && !selectedPropsTree.getText().isEmpty())
return Arrays.asList(selectedPropsTree.getText()); {
} return Arrays.asList(selectedPropsTree.getText());
List<Tree> children = (List<Tree>) selectedPropsTree.getChildren(); }
if (children!= null && !children.isEmpty()) List<Tree> children = (List<Tree>) selectedPropsTree.getChildren();
{ if (children != null && !children.isEmpty())
List<String> properties = new ArrayList<String>(children.size()); {
for (Tree child : children) { List<String> properties = new ArrayList<String>(children.size());
properties.add(child.getText()); for (Tree child : children)
} {
return properties; properties.add(child.getText());
} }
} return properties;
}
}
catch (RewriteCardinalityException re) catch (RewriteCardinalityException re)
{ {
//Catch any error so it doesn't get thrown up the stack //Catch any error so it doesn't get thrown up the stack
rpeLogger().debug("Unhandled Error parsing the "+paramName+" clause: "+re); rpeLogger().debug("Unhandled Error parsing the " + paramName + " clause: " + re);
} }
catch (RecognitionException e) catch (RecognitionException e)
{ {
rpeLogger().debug("Error parsing the \"+paramName+\" clause: "+param); rpeLogger().debug("Error parsing the \"+paramName+\" clause: " + param);
} }
catch (InvalidQueryException iqe) catch (InvalidQueryException iqe)
{ {
throw new InvalidSelectException(paramName, iqe.getQueryParam()); throw new InvalidSelectException(paramName, iqe.getQueryParam());
@@ -252,26 +249,33 @@ public interface RecognizedParamsExtractor
/** /**
* Takes the "where" parameter and turns it into a Java Object that can be used for querying * Takes the "where" parameter and turns it into a Java Object that can be used for querying
*
* @param whereParam String * @param whereParam String
* @return Query a parsed version of the where clause, represented in Java * @return Query a parsed version of the where clause, represented in Java
*/ */
default Query getWhereClause(String whereParam) throws InvalidQueryException default Query getWhereClause(String whereParam) throws InvalidQueryException
{ {
if (whereParam == null) return QueryImpl.EMPTY; if (whereParam == null)
return QueryImpl.EMPTY;
try { try
{
CommonTree whereTree = WhereCompiler.compileWhereClause(whereParam); CommonTree whereTree = WhereCompiler.compileWhereClause(whereParam);
if (whereTree instanceof CommonErrorNode) if (whereTree instanceof CommonErrorNode)
{ {
rpeLogger().debug("Error parsing the WHERE clause "+whereTree); rpeLogger().debug("Error parsing the WHERE clause " + whereTree);
throw new InvalidQueryException(whereTree); throw new InvalidQueryException(whereTree);
} }
return new QueryImpl(whereTree); return new QueryImpl(whereTree);
} catch (RewriteCardinalityException re) { //Catch any error so it doesn't get thrown up the stack }
rpeLogger().info("Unhandled Error parsing the WHERE clause: "+re); catch (RewriteCardinalityException re)
} catch (RecognitionException e) { { //Catch any error so it doesn't get thrown up the stack
whereParam += ", "+WhereCompiler.resolveMessage(e); rpeLogger().info("Unhandled Error parsing the WHERE clause: " + re);
rpeLogger().info("Error parsing the WHERE clause: "+whereParam); }
catch (RecognitionException e)
{
whereParam += ", " + WhereCompiler.resolveMessage(e);
rpeLogger().info("Error parsing the WHERE clause: " + whereParam);
} }
//Default to throw out an invalid query //Default to throw out an invalid query
throw new InvalidQueryException(whereParam); throw new InvalidQueryException(whereParam);
@@ -282,6 +286,7 @@ public interface RecognizedParamsExtractor
* The format is a comma seperated list of "columnName sortDirection", * The format is a comma seperated list of "columnName sortDirection",
* e.g. "name DESC, age ASC". It is not case sensitive and the sort direction is optional * e.g. "name DESC, age ASC". It is not case sensitive and the sort direction is optional
* It default to sort ASCENDING. * It default to sort ASCENDING.
*
* @param sortParams - String passed in on the request * @param sortParams - String passed in on the request
* @return - the sort columns or an empty list if the params were invalid. * @return - the sort columns or an empty list if the params were invalid.
*/ */
@@ -308,15 +313,16 @@ public interface RecognizedParamsExtractor
} }
else else
{ {
rpeLogger().debug("Invalid sort order definition ("+sortDef+"). Valid values are "+SortColumn.ASCENDING+" or "+SortColumn.DESCENDING+"."); rpeLogger().debug("Invalid sort order definition (" + sortDef + "). Valid values are " + SortColumn.ASCENDING + " or "
+ SortColumn.DESCENDING + ".");
} }
} }
sortedColumns.add(new SortColumn(columnName, SortColumn.ASCENDING.equals(sortOrder))); sortedColumns.add(new SortColumn(columnName, SortColumn.ASCENDING.equals(sortOrder)));
} }
// filteredProperties.add(); // filteredProperties.add();
} }
// logger.debug("Filtering using the following properties: " + filteredProperties); // logger.debug("Filtering using the following properties: " + filteredProperties);
// BeanPropertiesFilter filter = new BeanPropertiesFilter(filteredProperties); // BeanPropertiesFilter filter = new BeanPropertiesFilter(filteredProperties);
return sortedColumns; return sortedColumns;
} }
return Collections.emptyList(); return Collections.emptyList();
@@ -356,10 +362,8 @@ public interface RecognizedParamsExtractor
return Paging.valueOf(skipped, max); return Paging.valueOf(skipped, max);
} }
/** /**
* Takes the web request and looks for a "fields" parameter (otherwise deprecated "properties" parameter). * Takes the web request and looks for a "fields" parameter (otherwise deprecated "properties" parameter).
*
* Parses the parameter and produces a list of bean properties to use as a filter A * Parses the parameter and produces a list of bean properties to use as a filter A
* SimpleBeanPropertyFilter it returned that uses the bean properties. If no * SimpleBeanPropertyFilter it returned that uses the bean properties. If no
* filter param is set then a default BeanFilter is returned that will never * filter param is set then a default BeanFilter is returned that will never
@@ -367,7 +371,7 @@ public interface RecognizedParamsExtractor
* *
* @param filterParams String * @param filterParams String
* @return BeanPropertyFilter - if no parameter then returns a new * @return BeanPropertyFilter - if no parameter then returns a new
* ReturnAllBeanProperties class * ReturnAllBeanProperties class
*/ */
default BeanPropertiesFilter getFilter(String filterParams) default BeanPropertiesFilter getFilter(String filterParams)
{ {
@@ -383,7 +387,7 @@ public interface RecognizedParamsExtractor
* *
* @param filterParams String * @param filterParams String
* @return BeanPropertiesFilter - if no parameter then returns a new * @return BeanPropertiesFilter - if no parameter then returns a new
* ReturnAllBeanProperties class * ReturnAllBeanProperties class
*/ */
default Map<String, BeanPropertiesFilter> getRelationFilter(String filterParams) default Map<String, BeanPropertiesFilter> getRelationFilter(String filterParams)
{ {
@@ -414,7 +418,6 @@ public interface RecognizedParamsExtractor
return Collections.emptyMap(); return Collections.emptyMap();
} }
/** /**
* Finds all request parameters that aren't already know about (eg. not paging or filter params) * Finds all request parameters that aren't already know about (eg. not paging or filter params)
* and returns them for use. * and returns them for use.
@@ -424,10 +427,10 @@ public interface RecognizedParamsExtractor
*/ */
default Map<String, String[]> getRequestParameters(WebScriptRequest req) default Map<String, String[]> getRequestParameters(WebScriptRequest req)
{ {
if (req!= null) if (req != null)
{ {
String[] paramNames = req.getParameterNames(); String[] paramNames = req.getParameterNames();
if (paramNames!= null) if (paramNames != null)
{ {
Map<String, String[]> requestParameteters = new HashMap<String, String[]>(paramNames.length); Map<String, String[]> requestParameteters = new HashMap<String, String[]>(paramNames.length);

View File

@@ -23,6 +23,7 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.rest.framework.tools; package org.alfresco.rest.framework.tools;
import org.alfresco.rest.framework.core.exceptions.ApiException; import org.alfresco.rest.framework.core.exceptions.ApiException;
@@ -47,8 +48,8 @@ public interface RequestReader
/** /**
* Extracts the body contents from the request * Extracts the body contents from the request
* *
* @param req the request * @param req the request
* @param jsonHelper Jackson Helper * @param jsonHelper Jackson Helper
* @param requiredType the type to return * @param requiredType the type to return
* @return the Object in the required type * @return the Object in the required type
*/ */
@@ -74,8 +75,8 @@ public interface RequestReader
/** /**
* Extracts the body contents from the request as a List, the JSON can be an array or just a single value without the [] symbols * Extracts the body contents from the request as a List, the JSON can be an array or just a single value without the [] symbols
* *
* @param req the request * @param req the request
* @param jsonHelper Jackson Helper * @param jsonHelper Jackson Helper
* @param requiredType the type to return (without the List param) * @param requiredType the type to return (without the List param)
* @return A List of "Object" as the required type * @return A List of "Object" as the required type
*/ */
@@ -93,10 +94,9 @@ public interface RequestReader
} }
} }
default Log rrLogger() { default Log rrLogger()
{
return LogFactory.getLog(this.getClass()); return LogFactory.getLog(this.getClass());
} }
} }

View File

@@ -23,6 +23,7 @@
* along with Alfresco. If not, see <http://www.gnu.org/licenses/>. * along with Alfresco. If not, see <http://www.gnu.org/licenses/>.
* #L% * #L%
*/ */
package org.alfresco.rest.framework.tools; package org.alfresco.rest.framework.tools;
import org.alfresco.rest.framework.Api; import org.alfresco.rest.framework.Api;
@@ -66,7 +67,7 @@ public interface ResponseWriter
{ {
String UTF8 = "UTF-8"; String UTF8 = "UTF-8";
ContentInfo DEFAULT_JSON_CONTENT = new ContentInfoImpl(Format.JSON.mimetype(),UTF8, 0, null); ContentInfo DEFAULT_JSON_CONTENT = new ContentInfoImpl(Format.JSON.mimetype(), UTF8, 0, null);
Cache CACHE_NEVER = new Cache(new Description.RequiredCache() Cache CACHE_NEVER = new Cache(new Description.RequiredCache()
{ {
@Override @Override
@@ -90,13 +91,15 @@ public interface ResponseWriter
final WithResponse DEFAULT_SUCCESS = new WithResponse(Status.STATUS_OK, DEFAULT_JSON_CONTENT, CACHE_NEVER); final WithResponse DEFAULT_SUCCESS = new WithResponse(Status.STATUS_OK, DEFAULT_JSON_CONTENT, CACHE_NEVER);
default Log resWriterLogger() { default Log resWriterLogger()
{
return LogFactory.getLog(this.getClass()); return LogFactory.getLog(this.getClass());
} }
/** /**
* Sets the response headers with any information we know about the content * Sets the response headers with any information we know about the content
* @param res WebScriptResponse *
* @param res WebScriptResponse
* @param contentInfo Content Information * @param contentInfo Content Information
*/ */
default void setContentInfoOnResponse(WebScriptResponse res, ContentInfo contentInfo) default void setContentInfoOnResponse(WebScriptResponse res, ContentInfo contentInfo)
@@ -134,7 +137,6 @@ public interface ResponseWriter
/** /**
* The response status must be set before the response is written by Jackson (which will by default close and commit the response). * The response status must be set before the response is written by Jackson (which will by default close and commit the response).
* In a r/w txn, web script buffered responses ensure that it doesn't really matter but for r/o txns this is important. * In a r/w txn, web script buffered responses ensure that it doesn't really matter but for r/o txns this is important.
*
* If you set content information via the contentInfo object and ALSO the headers then "headers" will win because they are * If you set content information via the contentInfo object and ALSO the headers then "headers" will win because they are
* set last. * set last.
* *
@@ -144,17 +146,18 @@ public interface ResponseWriter
* @param contentInfo * @param contentInfo
* @param headers * @param headers
*/ */
default void setResponse(final WebScriptResponse res, int status, Cache cache, ContentInfo contentInfo, Map<String, List<String>> headers) default void setResponse(final WebScriptResponse res, int status, Cache cache, ContentInfo contentInfo, Map<String, List<String>> headers)
{ {
res.setStatus(status); res.setStatus(status);
if (cache != null) res.setCache(cache); if (cache != null) res.setCache(cache);
setContentInfoOnResponse(res,contentInfo); setContentInfoOnResponse(res,contentInfo);
if (headers != null && !headers.isEmpty()) if (headers != null && !headers.isEmpty())
{ {
for (Map.Entry<String, List<String>> header:headers.entrySet()) for (Map.Entry<String, List<String>> header : headers.entrySet())
{ {
for (int i=0; i < header.getValue().size(); i++) { for (int i = 0; i < header.getValue().size(); i++)
if (i==0) {
if (i == 0)
{ {
//If its the first one then set the header overwriting. //If its the first one then set the header overwriting.
res.setHeader(header.getKey(), header.getValue().get(i)); res.setHeader(header.getKey(), header.getValue().get(i));
@@ -171,6 +174,7 @@ public interface ResponseWriter
/** /**
* Sets the response using the WithResponse object * Sets the response using the WithResponse object
*
* @param res * @param res
* @param withResponse * @param withResponse
*/ */
@@ -181,29 +185,27 @@ public interface ResponseWriter
/** /**
* Renders a JSON error response * Renders a JSON error response
*
* @param errorResponse The error * @param errorResponse The error
* @param res web script response * @param res web script response
* @throws IOException * @throws IOException
*/ */
default void renderErrorResponse(final ErrorResponse errorResponse, final WebScriptResponse res, final JacksonHelper jsonHelper) throws IOException { default void renderErrorResponse(final ErrorResponse errorResponse, final WebScriptResponse res, final JacksonHelper jsonHelper)
throws IOException
{
String logId = ""; String logId = "";
if (Status.STATUS_INTERNAL_SERVER_ERROR == errorResponse.getStatusCode() || resWriterLogger().isDebugEnabled()) if (Status.STATUS_INTERNAL_SERVER_ERROR == errorResponse.getStatusCode() || resWriterLogger().isDebugEnabled())
{ {
logId = org.alfresco.util.GUID.generate(); logId = org.alfresco.util.GUID.generate();
resWriterLogger().error(logId+" : "+errorResponse.getStackTrace()); resWriterLogger().error(logId + " : " + errorResponse.getStackTrace());
} }
String stackMessage = I18NUtil.getMessage(DefaultExceptionResolver.STACK_MESSAGE_ID); String stackMessage = I18NUtil.getMessage(DefaultExceptionResolver.STACK_MESSAGE_ID);
final ErrorResponse errorToWrite = new ErrorResponse(errorResponse.getErrorKey(), final ErrorResponse errorToWrite = new ErrorResponse(errorResponse.getErrorKey(), errorResponse.getStatusCode(),
errorResponse.getStatusCode(), errorResponse.getBriefSummary(), stackMessage, logId, errorResponse.getAdditionalState(), DefaultExceptionResolver.ERROR_URL);
errorResponse.getBriefSummary(),
stackMessage,
logId,
errorResponse.getAdditionalState(),
DefaultExceptionResolver.ERROR_URL);
setContentInfoOnResponse(res, DEFAULT_JSON_CONTENT); setContentInfoOnResponse(res, DEFAULT_JSON_CONTENT);
@@ -216,7 +218,7 @@ public interface ResponseWriter
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
@Override @Override
public void writeContents(JsonGenerator generator, ObjectMapper objectMapper) public void writeContents(JsonGenerator generator, ObjectMapper objectMapper)
throws JsonGenerationException, JsonMappingException, IOException throws JsonGenerationException, JsonMappingException, IOException
{ {
JSONObject obj = new JSONObject(); JSONObject obj = new JSONObject();
obj.put("error", errorToWrite); obj.put("error", errorToWrite);
@@ -225,32 +227,32 @@ public interface ResponseWriter
}); });
} }
/** /**
* Renders an exception to the output stream as Json. * Renders an exception to the output stream as Json.
*
* @param exception * @param exception
* @param response * @param response
* @throws IOException * @throws IOException
*/ */
default void renderException(final Exception exception, final WebScriptResponse response, final ApiAssistant assistant) throws IOException { default void renderException(final Exception exception, final WebScriptResponse response, final ApiAssistant assistant) throws IOException
{
renderErrorResponse(assistant.resolveException(exception), response, assistant.getJsonHelper()); renderErrorResponse(assistant.resolveException(exception), response, assistant.getJsonHelper());
} }
/** /**
* Renders the result of an execution. * Renders the result of an execution.
* *
* @param res WebScriptResponse * @param res WebScriptResponse
* @param toSerialize result of an execution * @param toSerialize result of an execution
* @throws IOException * @throws IOException
*/ */
default void renderJsonResponse(final WebScriptResponse res, final Object toSerialize, final JacksonHelper jsonHelper) default void renderJsonResponse(final WebScriptResponse res, final Object toSerialize, final JacksonHelper jsonHelper) throws IOException
throws IOException
{ {
jsonHelper.withWriter(res.getOutputStream(), new JacksonHelper.Writer() jsonHelper.withWriter(res.getOutputStream(), new JacksonHelper.Writer()
{ {
@Override @Override
public void writeContents(JsonGenerator generator, ObjectMapper objectMapper) public void writeContents(JsonGenerator generator, ObjectMapper objectMapper)
throws JsonGenerationException, JsonMappingException, IOException throws JsonGenerationException, JsonMappingException, IOException
{ {
objectMapper.writeValue(generator, toSerialize); objectMapper.writeValue(generator, toSerialize);
} }