PL-8907 Rest API V2: queries params with list types

This commit is contained in:
Maxim Gorbunkov 2017-05-10 18:10:30 +04:00
parent 77f4529ba7
commit 556a7c63d1
6 changed files with 174 additions and 46 deletions

View File

@ -16,7 +16,11 @@
package com.haulmont.restapi.common;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.haulmont.chile.core.datatypes.Datatypes;
import com.haulmont.chile.core.datatypes.impl.*;
import com.haulmont.chile.core.model.MetaClass;
@ -26,14 +30,13 @@ import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.restapi.transform.JsonTransformationDirection;
import org.springframework.stereotype.Component;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.Collection;
import java.util.Date;
import java.util.UUID;
import java.util.*;
/**
*/
@ -49,7 +52,7 @@ public class RestParseUtils {
@Inject
protected Metadata metadata;
public Object toObject(Type type, String value, String modelVersion) throws ParseException {
public Object toObject(Type type, String value, @Nullable String modelVersion) throws ParseException {
if (value == null) return null;
Class clazz;
Class argumentTypeClass = null;
@ -129,4 +132,26 @@ public class RestParseUtils {
Gson gson = new Gson();
return gson.toJson(instance);
}
public Map<String, String> parseParamsJson(String paramsJson) {
Map<String, String> result = new LinkedHashMap<>();
if (Strings.isNullOrEmpty(paramsJson)) return result;
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = jsonParser.parse(paramsJson).getAsJsonObject();
for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
String paramName = entry.getKey();
JsonElement paramValue = entry.getValue();
if (paramValue.isJsonNull()) {
result.put(paramName, null);
} else if (paramValue.isJsonPrimitive()) {
result.put(paramName, paramValue.getAsString());
} else {
result.put(paramName, paramValue.toString());
}
}
return result;
}
}

View File

@ -69,7 +69,7 @@ public class EntitiesController {
String resultJson = entitiesControllerManager.loadEntitiesList(entityName, view, limit, offset, sort, returnNulls, dynamicAttributes, modelVersion);
ResponseEntity.BodyBuilder responseBuilder = ResponseEntity.status(HttpStatus.OK);
if (BooleanUtils.isTrue(returnCount)) {
String count = queriesControllerManager.getCount(entityName, RestQueriesConfiguration.ALL_ENTITIES_QUERY_NAME, modelVersion, new HashMap<>());
String count = queriesControllerManager.getCountGet(entityName, RestQueriesConfiguration.ALL_ENTITIES_QUERY_NAME, modelVersion, new HashMap<>());
responseBuilder.header("X-Total-Count", count);
}
return responseBuilder.body(resultJson);

View File

@ -40,7 +40,7 @@ public class QueriesController {
protected QueriesControllerManager queriesControllerManager;
@GetMapping("/{entityName}/{queryName}")
public ResponseEntity<String> executeQuery(@PathVariable String entityName,
public ResponseEntity<String> executeQueryGet(@PathVariable String entityName,
@PathVariable String queryName,
@RequestParam(required = false) Integer limit,
@RequestParam(required = false) Integer offset,
@ -50,21 +50,50 @@ public class QueriesController {
@RequestParam(required = false) Boolean returnCount,
@RequestParam(required = false) String modelVersion,
@RequestParam Map<String, String> params) {
String resultJson = queriesControllerManager.executeQuery(entityName, queryName, limit, offset, view, returnNulls, dynamicAttributes, modelVersion, params);
String resultJson = queriesControllerManager.executeQueryGet(entityName, queryName, limit, offset, view, returnNulls, dynamicAttributes, modelVersion, params);
ResponseEntity.BodyBuilder responseBuilder = ResponseEntity.status(HttpStatus.OK);
if (BooleanUtils.isTrue(returnCount)) {
String count = queriesControllerManager.getCount(entityName, queryName, modelVersion, params);
String count = queriesControllerManager.getCountGet(entityName, queryName, modelVersion, params);
responseBuilder.header("X-Total-Count", count);
}
return responseBuilder.body(resultJson);
}
@PostMapping("/{entityName}/{queryName}")
public ResponseEntity<String> executeQueryPost(@PathVariable String entityName,
@PathVariable String queryName,
@RequestParam(required = false) Integer limit,
@RequestParam(required = false) Integer offset,
@RequestParam(required = false) String view,
@RequestParam(required = false) Boolean returnNulls,
@RequestParam(required = false) Boolean dynamicAttributes,
@RequestParam(required = false) Boolean returnCount,
@RequestParam(required = false) String modelVersion,
@RequestBody String paramsJson) {
String resultJson = queriesControllerManager.executeQueryPost(entityName, queryName, limit, offset, view, returnNulls, dynamicAttributes, modelVersion, paramsJson);
ResponseEntity.BodyBuilder responseBuilder = ResponseEntity.status(HttpStatus.OK);
if (BooleanUtils.isTrue(returnCount)) {
String count = queriesControllerManager.getCountPost(entityName, queryName, modelVersion, paramsJson);
responseBuilder.header("X-Total-Count", count);
}
return responseBuilder.body(resultJson);
}
@GetMapping(value = "/{entityName}/{queryName}/count", produces = "text/plain;charset=UTF-8")
public String getCount(@PathVariable String entityName,
public String getCountGet(@PathVariable String entityName,
@PathVariable String queryName,
@RequestParam(required = false) String modelVersion,
@RequestParam Map<String, String> params) throws ClassNotFoundException, ParseException {
return queriesControllerManager.getCount(entityName, queryName, modelVersion, params);
return queriesControllerManager.getCountGet(entityName, queryName, modelVersion, params);
}
@PostMapping(value = "/{entityName}/{queryName}/count", produces = "text/plain;charset=UTF-8")
public String getCountPost(@PathVariable String entityName,
@PathVariable String queryName,
@RequestParam(required = false) String modelVersion,
@RequestBody String paramsJson) throws ClassNotFoundException, ParseException {
return queriesControllerManager.getCountPost(entityName, queryName, modelVersion, paramsJson);
}
@GetMapping("/{entityName}")

View File

@ -17,6 +17,9 @@
package com.haulmont.restapi.service;
import com.google.common.base.Strings;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;
import com.haulmont.chile.core.datatypes.Datatypes;
import com.haulmont.chile.core.datatypes.impl.*;
import com.haulmont.chile.core.model.MetaClass;
@ -30,6 +33,7 @@ import com.haulmont.cuba.core.global.Metadata;
import com.haulmont.cuba.core.global.Security;
import com.haulmont.cuba.security.entity.EntityOp;
import com.haulmont.restapi.common.RestControllerUtils;
import com.haulmont.restapi.common.RestParseUtils;
import com.haulmont.restapi.exception.RestAPIException;
import com.haulmont.restapi.config.RestQueriesConfiguration;
import com.haulmont.restapi.transform.JsonTransformationDirection;
@ -40,6 +44,7 @@ import org.springframework.util.ClassUtils;
import javax.annotation.Nullable;
import javax.inject.Inject;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.text.ParseException;
import java.util.*;
@ -68,15 +73,35 @@ public class QueriesControllerManager {
@Inject
protected PersistenceManagerClient persistenceManagerClient;
public String executeQuery(String entityName,
String queryName,
@Nullable Integer limit,
@Nullable Integer offset,
@Nullable String viewName,
@Nullable Boolean returnNulls,
@Nullable Boolean dynamicAttributes,
@Nullable String version,
Map<String, String> params) {
@Inject
protected RestParseUtils restParseUtils;
public String executeQueryGet(String entityName,
String queryName,
@Nullable Integer limit,
@Nullable Integer offset,
@Nullable String viewName,
@Nullable Boolean returnNulls,
@Nullable Boolean dynamicAttributes,
@Nullable String version,
Map<String, String> params) {
return _executeQuery(entityName, queryName, limit, offset, viewName, returnNulls, dynamicAttributes, version, params);
}
public String executeQueryPost(String entityName,
String queryName,
@Nullable Integer limit,
@Nullable Integer offset,
@Nullable String viewName,
@Nullable Boolean returnNulls,
@Nullable Boolean dynamicAttributes,
@Nullable String version,
String paramsJson) {
Map<String, String> paramsMap = restParseUtils.parseParamsJson(paramsJson);
return _executeQuery(entityName, queryName, limit, offset, viewName, returnNulls, dynamicAttributes, version, paramsMap);
}
protected String _executeQuery(String entityName, String queryName, @Nullable Integer limit, @Nullable Integer offset, @Nullable String viewName, @Nullable Boolean returnNulls, @Nullable Boolean dynamicAttributes, @Nullable String version, Map<String, String> params) {
LoadContext<Entity> ctx;
entityName = restControllerUtils.transformEntityNameIfRequired(entityName, version, JsonTransformationDirection.FROM_VERSION);
try {
@ -104,10 +129,22 @@ public class QueriesControllerManager {
return json;
}
public String getCount(String entityName,
String queryName,
String version,
Map<String, String> params) {
public String getCountGet(String entityName,
String queryName,
String version,
Map<String, String> params) {
return _getCount(entityName, queryName, version, params);
}
public String getCountPost(String entityName,
String queryName,
String version,
String paramsJson) {
Map<String, String> paramsMap = restParseUtils.parseParamsJson(paramsJson);
return _getCount(entityName, queryName, version, paramsMap);
}
protected String _getCount(String entityName, String queryName, String version, Map<String, String> params) {
entityName = restControllerUtils.transformEntityNameIfRequired(entityName, version, JsonTransformationDirection.FROM_VERSION);
LoadContext<Entity> ctx;
try {
@ -180,6 +217,20 @@ public class QueriesControllerManager {
}
protected Object toObject(Class clazz, String value) throws ParseException {
if (clazz.isArray()) {
Class componentType = clazz.getComponentType();
JsonParser jsonParser = new JsonParser();
JsonArray jsonArray = jsonParser.parse(value).getAsJsonArray();
List result = new ArrayList();
for (JsonElement jsonElement : jsonArray) {
String stringValue = (jsonElement.isJsonPrimitive() && jsonElement.getAsJsonPrimitive().isString()) ?
jsonElement.getAsJsonPrimitive().getAsString() :
jsonElement.toString();
Object arrayElementValue = toObject(componentType, stringValue);
result.add(arrayElementValue);
}
return result;
}
if (String.class == clazz) return value;
if (Integer.class == clazz || Integer.TYPE == clazz
|| Byte.class == clazz || Byte.TYPE == clazz

View File

@ -84,7 +84,7 @@ public class ServicesControllerManager {
@Nullable
public ServiceCallResult invokeServiceMethodPost(String serviceName, String methodName, String paramsJson, String modelVersion) {
Map<String, String> paramsMap = parseParamsJson(paramsJson);
Map<String, String> paramsMap = restParseUtils.parseParamsJson(paramsJson);
List<String> paramNames = new ArrayList<>(paramsMap.keySet());
List<String> paramValuesStr = new ArrayList<>(paramsMap.values());
return _invokeServiceMethod(serviceName, methodName, paramNames, paramValuesStr, modelVersion);
@ -104,28 +104,6 @@ public class ServicesControllerManager {
return serviceInfo;
}
private Map<String, String> parseParamsJson(String paramsJson) {
Map<String, String> result = new LinkedHashMap<>();
if (Strings.isNullOrEmpty(paramsJson)) return result;
JsonParser jsonParser = new JsonParser();
JsonObject jsonObject = jsonParser.parse(paramsJson).getAsJsonObject();
for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
String paramName = entry.getKey();
JsonElement paramValue = entry.getValue();
if (paramValue.isJsonNull()) {
result.put(paramName, null);
} else if (paramValue.isJsonPrimitive()) {
result.put(paramName, paramValue.getAsString());
} else {
result.put(paramName, paramValue.toString());
}
}
return result;
}
@Nullable
protected ServiceCallResult _invokeServiceMethod(String serviceName, String methodName, List<String> paramNames,
List<String> paramValuesStr, String modelVersion) {

View File

@ -779,6 +779,29 @@ paths:
schema:
$ref: '#/definitions/error'
post:
tags:
- Queries
summary: Execute a query
description: |
Executes a predefined query. Query parameters must be passed in the request body as JSON map.
responses:
200:
description: Success. A list of entitie is returned in the response body.
schema:
type: array
items:
$ref: '#/definitions/entityFull'
403:
description: Forbidden. The user doesn't have permissions to read the entity.
schema:
$ref: '#/definitions/error'
404:
description: |
MetaClass not found or query with the given name not found
schema:
$ref: '#/definitions/error'
/queries/{entityName}/{queryName}/count:
parameters:
- $ref: '#/parameters/entityNameParam'
@ -805,6 +828,28 @@ paths:
MetaClass not found or query with the given name not found
schema:
$ref: '#/definitions/error'
post:
tags:
- Queries
summary: Return a number of entities in query result
description: |
Returns a number of entities that matches the query. You can use the `all` keyword for the `queryNameParam`
to get the number of all available entities.
responses:
200:
description: Success
schema:
title: Count
type: integer
403:
description: Forbidden. The user doesn't have permissions to read the entity.
schema:
$ref: '#/definitions/error'
404:
description: |
MetaClass not found or query with the given name not found
schema:
$ref: '#/definitions/error'
############################### Services #######################################
/services/{serviceName}: