Skip to content

Instantly share code, notes, and snippets.

@ascott42
Last active September 25, 2020 05:59
Show Gist options
  • Save ascott42/ea9b2dec6487b3e30b7c828ecc480a4f to your computer and use it in GitHub Desktop.
Save ascott42/ea9b2dec6487b3e30b7c828ecc480a4f to your computer and use it in GitHub Desktop.
Querydsl Predicate/OrderSpecifier into JSON
package com.asis.kis.persistence.core.querydsl;
import com.asis.kis.base.commons.stream.SimpleStreams;
import com.asis.kis.commons.util.JsonTypeConverter;
import com.asis.kis.commons.util.Jsons;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.CaseFormat;
import com.google.common.collect.Lists;
import com.querydsl.core.types.EntityPath;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.Order;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.dsl.BooleanExpression;
import com.querydsl.core.types.dsl.Expressions;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.core.types.dsl.PathBuilderValidator;
import restx.factory.Component;
import java.util.*;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import static com.querydsl.core.types.dsl.Expressions.constant;
/**
* Permits to deserialize a json predicate and orderBys into queryDSL object.
*/
public class DefaultQueryDslDeserializer implements QueryDslDeserializer {
/**
* the jackson object mapper
*/
protected final ObjectMapper mapper;
/**
* The value converter
*/
protected final JsonTypeConverter converter;
/**
* Default constructor of {@link DefaultQueryDslDeserializer}
*/
public DefaultQueryDslDeserializer() {
this.mapper = Jsons.buildMapper();
this.converter = new JsonTypeConverter();
}
/**
* Create a queryDSL predicate from the specified json
*
* @param json the json predicate
* @param entityClass the root entity class
* @return the queryDSL predicate
*/
public BooleanExpression deserializePredicate(String json, Class<?> entityClass) {
try {
JsonNode jsonNode = mapper.readTree(json);
return buildPredicates(jsonNode, entityClass);
} catch (Exception e) {
throw new DSLJsonDeserializerException("Unable to deserialize json in queryDSL predicate", e);
}
}
/**
* Create a collection of queryDSL order bys from the specified json
*
* @param json the json order bys
* @param entityClass the root entity class
* @return the collection of queryDSL order bys
*/
public List<OrderSpecifier> deserializeOrderBys(String json, Class<?> entityClass) {
try {
JsonNode jsonNode = mapper.readTree(json);
return buildOrderBys(jsonNode, entityClass);
} catch (Exception e) {
throw new DSLJsonDeserializerException("Unable to deserialize json in queryDSL order bys", e);
}
}
/**
* Build all order specifier from the specified JSONObject
*/
private List<OrderSpecifier> buildOrderBys(JsonNode rootNode, Class<?> entityClass) {
return SimpleStreams
.of(rootNode::fields)
.map(node -> buildPathAndOrderBy(node.getKey(), node.getValue(), entityClass))
.flatMap(Collection::stream)
.collect(Collectors.toList());
}
/**
* Build an order by expression
*/
protected List<OrderSpecifier> buildPathAndOrderBy(String key, JsonNode value, Class<?> entityClass) {
EntityPath entityPath = buildPath(key, entityClass);
return buildOrderBy(entityPath, value);
}
@SuppressWarnings("unchecked")
protected List<OrderSpecifier> buildOrderBy(EntityPath entityPath, JsonNode value) {
if (!value.isObject() && value.isTextual()) {
return Lists.newArrayList(new OrderSpecifier(convert(value.asText(), Order.class), entityPath));
}
throw new IllegalArgumentException("The object value have to be a string : " + value.toString());
}
/**
* Build all predicates from the specified map
*/
protected BooleanExpression buildPredicates(JsonNode rootNode, Class<?> entityClass) {
List<BooleanExpression> expressions = SimpleStreams
.of(rootNode::fields)
.map(node -> buildPredicate(node.getKey(), node.getValue(), entityClass))
.collect(Collectors.toList());
return Expressions.allOf(expressions.toArray(new BooleanExpression[expressions.size()]));
}
/**
* Build a predicate with the specified key and object value
*/
protected BooleanExpression buildPredicate(String key, JsonNode nodeValue, Class<?> entityClass) {
Optional<QueryDslOperator> operator = getOperator(key);
if (operator.isPresent()) {
// the key is an operator
// it is an array of and or or predicates
return buildOrAndPredicate(nodeValue, operator.get(), entityClass);
} else {
// build the path
EntityPath entityPath = buildPath(key, entityClass);
return buildBasePredicate(entityPath, nodeValue);
}
}
/**
* Build base predicate : path - operator - value
*/
protected BooleanExpression buildBasePredicate(EntityPath entityPath, JsonNode nodeValue) {
List<Expression> expressions = new ArrayList<>();
// add the path to the expressions list
expressions.add(entityPath);
QueryDslOperator valueOp = QueryDslOperator.EQ;
// if it is an object like { "$lt" : "value" }
if (nodeValue.isObject()) {
Iterator<Entry<String, JsonNode>> fields = nodeValue.fields();
while (fields.hasNext()) {
Entry<String, JsonNode> objectNode = fields.next();
// the key is the operator
valueOp = QueryDslOperator.getFromJson(objectNode.getKey());
if (valueOp.equals(QueryDslOperator.BETWEEN)) {
SimpleStreams
.of(() -> objectNode.getValue().elements())
.forEach(v -> expressions.add(createValue(v, entityPath)));
} else if (valueOp.equals(QueryDslOperator.IN) || valueOp.equals(QueryDslOperator.NOT_IN)) {
expressions.add(constant(
SimpleStreams.of(() -> objectNode.getValue().elements())
.map(v -> (Object) convert(v.asText(), entityPath.getType()))
.collect(Collectors.toList())));
} else {
// simple value
expressions.add(createValue(objectNode.getValue(), entityPath));
}
}
} else {
// it is a value
expressions.add(createValue(nodeValue, entityPath));
}
return Expressions.predicate(valueOp.getDSLOperator(), expressions.toArray(new Expression[expressions.size()]));
}
/**
* create a queryDSL constant value for the given json node
*/
protected Expression createValue(JsonNode value, EntityPath entityPath) {
return constant(convert(value.asText(), entityPath.getType()));
}
/**
* Build a predicate with operator and, or (array of predicates)
*/
protected BooleanExpression buildOrAndPredicate(JsonNode nodeValue, QueryDslOperator operator, Class<?> entityClass) {
List<BooleanExpression> booleanExpressions = new ArrayList<>();
// the key is an operator ($and - $or - ...)
if (nodeValue.isArray()) {
Iterator<JsonNode> elements = nodeValue.elements();
while (elements.hasNext()) {
JsonNode element = elements.next();
if (element.isObject()) {
booleanExpressions.add(buildPredicates(element, entityClass));
} else {
throw new IllegalStateException("expected to have an object instead of " + element.toString());
}
}
if (operator.equals(QueryDslOperator.AND)) {
return Expressions.allOf(booleanExpressions.toArray(new BooleanExpression[booleanExpressions.size()]));
} else if (operator.equals(QueryDslOperator.OR)) {
return Expressions.anyOf(booleanExpressions.toArray(new BooleanExpression[booleanExpressions.size()]));
} else {
throw new IllegalStateException("Don't supported operator here : " + operator);
}
} else {
throw new IllegalStateException("expected to have an array type instead of "
+ nodeValue.toString());
}
}
/**
* Cast the json string value into an object of the associated field type
*
* @param value the string value
* @param type the field type
* @return the value transformed into the associated field type
*/
protected <T> T convert(String value, Class<T> type) {
return converter.convert(value, type);
}
/**
* Build a queryDSL path from the specified string path
*
* @param path the string path. ex : content.product.packaging
* @param entityClass the entity root class
* @return the queryDSL path
*/
@SuppressWarnings("unchecked")
protected EntityPath<?> buildPath(String path, Class entityClass) {
String[] paths = path.split("\\.");
if (paths.length > 0) {
PathBuilder builder = new PathBuilder(entityClass, paths[0], PathBuilderValidator.FIELDS);
for (int i = 1; i < paths.length; i++) {
builder = builder.get(paths[i]);
}
return builder;
} else {
throw new IllegalArgumentException("The specified path is incorrect : " + path);
}
}
/**
* Get the JSONOperator from the json value
*
* @param operator the json operator value
* @return optional operator
*/
protected Optional<QueryDslOperator> getOperator(String operator) {
try {
return Optional.of(QueryDslOperator.getFromJson(operator));
} catch (Exception e) {
return Optional.empty();
}
}
/**
* QueryDslToJsonDeserializer exception
*/
public static class DSLJsonDeserializerException extends RuntimeException {
public DSLJsonDeserializerException(String message, Throwable cause) {
super(message, cause);
}
}
}
package com.asis.kis.persistence.core.querydsl;
import com.asis.kis.persistence.core.querydsl.domain.Content;
import com.google.common.collect.Lists;
import com.querydsl.core.types.Expression;
import com.querydsl.core.types.OrderSpecifier;
import org.joda.time.DateTime;
import org.junit.Test;
import java.util.Date;
import java.util.List;
import static com.asis.kis.persistence.core.querydsl.domain.QContent.content;
import static com.asis.kis.persistence.core.querydsl.domain.ReplenishmentMode.FIRST_EXPIRED_FIRST_OUT;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit test of {@link DefaultQueryDslDeserializer}
*
* @author aescot
*/
public class DefaultQueryDslDeserializerTest {
private DefaultQueryDslDeserializer deserializer = new DefaultQueryDslDeserializer();
@Test
public void should_deserialize_string_equal_predicate() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.support.location.zone\":\"ZONE2\"}", Content.class);
assertThat(content.support().location().zone.eq("ZONE2")).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_string_integer() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.product.price\":{\"$lte\":699}}", Content.class);
assertThat(content.product().price.loe(699)).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_long_and_gt_operator() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.quantity\":{\"$gt\":10}}", Content.class);
assertThat(content.quantity.gt(Long.parseLong("10"))).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_start_with_operator() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.support.location.zone\":{\"$start\":\"ZONE\"}}", Content.class);
assertThat(content.support().location().zone.startsWith("ZONE")).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_end_with_operator() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.support.location.zone\":{\"$end\":\"ZONE\"}}", Content.class);
assertThat(content.support().location().zone.endsWith("ZONE")).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_contains_operator() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.support.location.zone\":{\"$contains\":\"ZONE\"}}", Content.class);
assertThat(content.support().location().zone.contains("ZONE")).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_like_operator() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.support.location.zone\":{\"$like\":\"ZONE\"}}", Content.class);
assertThat(content.support().location().zone.like("ZONE")).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_lt_operator() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.quantity\":{\"$lt\":10}}", Content.class);
assertThat(content.quantity.lt(10)).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_loe_operator() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.quantity\":{\"$lte\":10}}", Content.class);
assertThat(content.quantity.loe(10)).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_gt_operator() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.quantity\":{\"$gt\":10}}", Content.class);
assertThat(content.quantity.gt(10)).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_enum_field_type() {
Expression predicate = deserializer.deserializePredicate("{\"content.product.replenishmentMode\":\"FIRST_EXPIRED_FIRST_OUT\"}", Content.class);
assertThat(content.product().replenishmentMode.eq(FIRST_EXPIRED_FIRST_OUT)).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_between_operator() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.quantity\":{\"$between\":[10,100]}}", Content.class);
assertThat(content.quantity.between(10, 100)).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_date() {
Expression predicate = deserializer.deserializePredicate("{\"content.createdDate\":\"2015-05-01T14:00:00.000+0000\"}", Content.class);
Date date = new DateTime(2015, 5, 1, 16, 0).toDate();
assertThat(content.createdDate.eq(date)).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_and_operator() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"content.support.location.zone\":\"ZONE1\",\"content.quantity\":{\"$gt\":10}"
+ ",\"content.product.replenishmentMode\":\"FIRST_EXPIRED_FIRST_OUT\"}", Content.class);
assertThat(content.support().location().zone.eq("ZONE1")
.and(content.quantity.gt(10))
.and(content.product().replenishmentMode.eq(FIRST_EXPIRED_FIRST_OUT))).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_or_operator() throws Exception {
Expression predicate = deserializer.deserializePredicate("{\"$or\":[{\"content.support.location.zone\":\"ZONE1\"},{\"content.quantity\":{\"$gt\":10}}]}", Content.class);
assertThat(content.support().location().zone.eq("ZONE1")
.or(content.quantity.gt(10))).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_nested_or_and_predicate() {
// nested or predicate
Expression predicate = deserializer.deserializePredicate("{\"content.support.location.zone\":\"ZONE1\",\"$or\":[{\"content.product.replenishmentMode\":\"FIRST_EXPIRED_FIRST_OUT\"},{\"content.quantity\":{\"$gt\":10}}]}", Content.class);
assertThat(content.support().location().zone.eq("ZONE1")
.and(content.product().replenishmentMode.eq(FIRST_EXPIRED_FIRST_OUT)
.or(content.quantity.gt(10)))).isEqualTo(predicate);
// or predicate with nested and
predicate = deserializer.deserializePredicate("{\"$or\":[{\"content.support.location.zone\":\"ZONE1\"},{\"content.product.replenishmentMode\":\"FIRST_EXPIRED_FIRST_OUT\",\"content.quantity\":{\"$gt\":10}}]}", Content.class);
assertThat(content.support().location().zone.eq("ZONE1")
.or(content.product().replenishmentMode.eq(FIRST_EXPIRED_FIRST_OUT)
.and(content.quantity.gt(10)))).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_in_operator() {
Expression predicate = deserializer.deserializePredicate("{\"content.packaging\":{\"$in\":[\"a\",\"b\",\"c\"]}}", Content.class);
assertThat(content.packaging.in("a", "b", "c")).isEqualTo(predicate);
}
@Test
public void should_deserialize_predicate_with_not_in_operator() {
Expression predicate = deserializer.deserializePredicate("{\"content.quantity\":{\"$nin\":[10,100,99]}}", Content.class);
assertThat(content.quantity.notIn(10,100,99)).isEqualTo(predicate);
}
@Test
public void should_deserialize_simple_order_by() {
List<OrderSpecifier> orders = deserializer.deserializeOrderBys("{\"content.quantity\":\"ASC\"}", Content.class);
assertThat(Lists.<OrderSpecifier>newArrayList(content.quantity.asc())).isEqualTo(orders);
}
@Test
public void should_deserialize_multiple_order_by() {
List<OrderSpecifier> orders = deserializer.deserializeOrderBys("{\"content.quantity\":\"ASC\",\"content.support.location.zone\":\"DESC\"}", Content.class);
assertThat(Lists.<OrderSpecifier>newArrayList(content.quantity.asc(), content.support().location().zone.desc())).isEqualTo(orders);
}
}
package com.asis.kis.persistence.core.querydsl;
import java.util.Collection;
import java.util.List;
import javax.annotation.Nullable;
import com.asis.kis.commons.util.Jsons;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.querydsl.core.types.*;
import restx.factory.Component;
/**
* Permits to serialize in json a queryDSL predicate and order
*/
public class DefaultQueryDslSerializer implements Visitor<Object, Void>, QueryDslSerializer {
protected final ObjectMapper mapper;
public DefaultQueryDslSerializer() {
this.mapper = Jsons.buildMapper();
}
/**
* Serialize the specified list of orderBys
*
* @param orderBys collection of orderBys
* @return the json of the queryDSl orders
*/
public JsonNode serializeAsNode(List<OrderSpecifier> orderBys) {
ObjectNode node = mapper.createObjectNode();
for (OrderSpecifier<?> orderBy : orderBys) {
Object key = orderBy.getTarget().accept(this, null);
node.put(key.toString(), orderBy.getOrder().toString());
}
return node;
}
/**
* Serialize the specified expression in the json object representation
*
* @param expression the queryDSL expression
* @return a expressions object (the json object representation)
*/
public JsonNode serializeAsNode(Expression<?> expression) {
return mapper.valueToTree(expression.accept(this, null));
}
protected ObjectNode asJsonObject(String key, Object value) {
return (ObjectNode) mapper.createObjectNode().set(key, mapper.valueToTree(value));
}
protected ObjectNode asJsonObject(QueryDslOperator op, Object value) {
return asJsonObject(op.getJson(), value);
}
private String asJsonKey(Operation<?> expr, int index) {
return (String) asJsonValue(expr, index);
}
private Object asJsonValue(Operation<?> expr, int index) {
return expr.getArg(index).accept(this, null);
}
@Nullable
@Override
public Object visit(Constant<?> expr, @Nullable Void context) {
if (Enum.class.isAssignableFrom(expr.getType())) {
return ((Enum<?>) expr.getConstant()).name();
} else {
return expr.getConstant();
}
}
@Nullable
@Override
public Object visit(Operation<?> expr, @Nullable Void context) {
Operator op = expr.getOperator();
if (op == Ops.EQ) {
return asJsonObject(asJsonKey(expr, 0), asJsonValue(expr, 1));
} else if (op == Ops.STRING_IS_EMPTY) {
return asJsonObject(asJsonKey(expr, 0), "");
} else if (op == Ops.AND) {
ObjectNode lhs = (ObjectNode) serializeAsNode(expr.getArg(0));
ObjectNode rhs = (ObjectNode) serializeAsNode(expr.getArg(1));
lhs.setAll(rhs);
return lhs;
} else if (op == Ops.OR) {
ArrayNode arrayNode = mapper.createArrayNode()
.add(serializeAsNode(expr.getArg(0)))
.add(serializeAsNode(expr.getArg(1)));
return asJsonObject(QueryDslOperator.getFromDsl(op), arrayNode);
} else if (op == Ops.BETWEEN) {
ArrayNode arrayNode = mapper.createArrayNode()
.add(serializeAsNode(expr.getArg(1)))
.add(serializeAsNode(expr.getArg(2)));
return asJsonObject(asJsonKey(expr, 0), asJsonObject(QueryDslOperator.getFromDsl(op), arrayNode));
} else if (op == Ops.IN || op.equals(Ops.NOT_IN)) {
int constIndex = 1;
if (Collection.class.isAssignableFrom(expr.getArg(constIndex).getType())) {
@SuppressWarnings("unchecked") //guarded by previous check
Collection<?> values = ((Constant<? extends Collection<?>>) expr.getArg(constIndex)).getConstant();
return asJsonObject(asJsonKey(expr, 0), asJsonObject(QueryDslOperator.getFromDsl(op), values.toArray()));
}
} else if (op == Ops.NE || op == Ops.STARTS_WITH || op == Ops.ENDS_WITH
|| op == Ops.STRING_CONTAINS || op == Ops.LIKE || op == Ops.LT
|| op == Ops.GT || op == Ops.LOE || op == Ops.GOE) {
return asJsonObject(asJsonKey(expr, 0), asJsonObject(QueryDslOperator.getFromDsl(op), asJsonValue(expr, 1)));
}
throw new UnsupportedOperationException("Illegal operation " + expr);
}
@Nullable
@Override
public Object visit(Path<?> expr, @Nullable Void context) {
PathMetadata metadata = expr.getMetadata();
if (metadata.getParent() != null) {
if (metadata.getPathType() == PathType.COLLECTION_ANY) {
return visit(metadata.getParent(), context);
} else {
String rv = getKeyForPath(metadata);
return visit(metadata.getParent(), context) + "." + rv;
}
}
return getKeyForPath(metadata);
}
protected String getKeyForPath(PathMetadata metadata) {
return metadata.getElement().toString();
}
@Nullable
@Override
public Object visit(SubQueryExpression<?> expr, @Nullable Void context) {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public Object visit(TemplateExpression<?> expr, @Nullable Void context) {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public Object visit(ParamExpression<?> expr, @Nullable Void context) {
throw new UnsupportedOperationException();
}
@Nullable
@Override
public Object visit(FactoryExpression<?> expr, @Nullable Void context) {
throw new UnsupportedOperationException();
}
}
package com.asis.kis.persistence.core.querydsl;
import com.asis.kis.persistence.core.querydsl.domain.ReplenishmentMode;
import org.joda.time.DateTime;
import org.junit.Test;
import java.util.Date;
import static com.asis.kis.persistence.core.querydsl.domain.QContent.content;
import static org.assertj.core.api.Assertions.assertThat;
/**
* Unit test of {@link QueryDslSerializer}
*/
public class DefaultQueryDslSerializerTest {
private QueryDslSerializer serializer = new DefaultQueryDslSerializer();
@Test
public void should_serialize_in_json_equal_predicate() throws Exception {
String json = serializer.serialize(content.support().location().zone.eq("ZONE1"));
assertThat(json).isEqualTo("{\"content.support.location.zone\":\"ZONE1\"}");
}
@Test
public void should_serialize_in_json_not_equal_predicate() throws Exception {
String json = serializer.serialize(content.quantity.ne((long) 100));
assertThat(json).isEqualTo("{\"content.quantity\":{\"$ne\":100}}");
}
@Test
public void should_serialize_in_json_empty_string_predicate() throws Exception {
String json = serializer.serialize(content.support().location().zone.isEmpty());
assertThat(json).isEqualTo("{\"content.support.location.zone\":\"\"}");
}
@Test
public void should_serialize_in_json_and_predicate() throws Exception {
// simple and
String json = serializer.serialize(
content.support().location().zone.eq("ZONE1")
.and(content.packaging.isEmpty()));
assertThat(json).isEqualTo("{\"content.support.location.zone\":\"ZONE1\",\"content.packaging\":\"\"}");
// multiple and
json = serializer.serialize(
content.support().location().zone.eq("ZONE1")
.and(content.packaging.isEmpty()
.and(content.quantity.gt(10))));
assertThat(json).isEqualTo("{\"content.support.location.zone\":\"ZONE1\",\"content.packaging\":\"\",\"content.quantity\":{\"$gt\":10}}");
}
@Test
public void should_serialize_in_json_or_predicate() throws Exception {
String json = serializer.serialize(
content.support().location().zone.eq("ZONE1")
.or(content.packaging.isEmpty()));
assertThat(json).isEqualTo("{\"$or\":[{\"content.support.location.zone\":\"ZONE1\"},{\"content.packaging\":\"\"}]}");
}
@Test
public void should_serialize_in_json_nested_or_and_predicate() {
String json = serializer.serialize(
content.support().location().zone.eq("ZONE1").and(content.packaging.isEmpty()
.or(content.quantity.gt(10))));
assertThat(json).isEqualTo("{\"content.support.location.zone\":\"ZONE1\",\"$or\":[{\"content.packaging\":\"\"},{\"content.quantity\":{\"$gt\":10}}]}");
// or predicate
json = serializer.serialize(
content.support().location().zone.eq("ZONE1")
.or(content.packaging.isEmpty()
.and(content.quantity.gt(10))));
assertThat(json).isEqualTo("{\"$or\":[{\"content.support.location.zone\":\"ZONE1\"},{\"content.packaging\":\"\",\"content.quantity\":{\"$gt\":10}}]}");
}
@Test
public void should_serialize_in_json_start_with_predicate() throws Exception {
String json = serializer.serialize(content.support().location().zone.startsWith("ZONE"));
assertThat(json).isEqualTo("{\"content.support.location.zone\":{\"$start\":\"ZONE\"}}");
}
@Test
public void should_serialize_in_json_end_with_predicate() throws Exception {
String json = serializer.serialize(content.support().location().zone.endsWith("ZONE"));
assertThat(json).isEqualTo("{\"content.support.location.zone\":{\"$end\":\"ZONE\"}}");
}
@Test
public void should_serialize_in_json_contains_predicate() throws Exception {
String json = serializer.serialize(content.support().location().zone.contains("ZONE"));
assertThat(json).isEqualTo("{\"content.support.location.zone\":{\"$contains\":\"ZONE\"}}");
}
@Test
public void should_serialize_in_json_like_predicate() throws Exception {
String json = serializer.serialize(content.support().location().zone.like("ZONE"));
assertThat(json).isEqualTo("{\"content.support.location.zone\":{\"$like\":\"ZONE\"}}");
}
@Test
public void should_serialize_in_json_between_predicate() throws Exception {
String json = serializer.serialize(content.quantity.between(10, 100));
assertThat(json).isEqualTo("{\"content.quantity\":{\"$between\":[10,100]}}");
}
@Test
public void should_serialize_in_json_lt_predicate() throws Exception {
String json = serializer.serialize(content.quantity.lt(10));
assertThat(json).isEqualTo("{\"content.quantity\":{\"$lt\":10}}");
}
@Test
public void should_serialize_in_json_loe_predicate() throws Exception {
String json = serializer.serialize(content.quantity.loe(10));
assertThat(json).isEqualTo("{\"content.quantity\":{\"$lte\":10}}");
}
@Test
public void should_serialize_in_json_gt_predicate() throws Exception {
String json = serializer.serialize(content.quantity.gt(10));
assertThat(json).isEqualTo("{\"content.quantity\":{\"$gt\":10}}");
}
@Test
public void should_serialize_in_json_goe_predicate() throws Exception {
String json = serializer.serialize(content.quantity.goe(10));
assertThat(json).isEqualTo("{\"content.quantity\":{\"$gte\":10}}");
}
@Test
public void should_serialize_in_json_orders() {
String json = serializer.serialize(content.quantity.asc());
assertThat(json).isEqualTo("{\"content.quantity\":\"ASC\"}");
}
@Test
public void should_serialize_in_json_multiple_orders() {
String json = serializer.serialize(content.quantity.asc(), content.support().location().zone.desc());
assertThat(json).isEqualTo("{\"content.quantity\":\"ASC\",\"content.support.location.zone\":\"DESC\"}");
}
@Test
public void should_serialize_predicate_with_enum_field() {
String json = serializer.serialize(content.product().replenishmentMode.eq(ReplenishmentMode.FIRST_EXPIRED_FIRST_OUT));
assertThat(json).isEqualTo("{\"content.product.replenishmentMode\":\"FIRST_EXPIRED_FIRST_OUT\"}");
}
@Test
public void should_serialize_predicate_with_date_field() {
Date date = new DateTime(2015, 5, 1, 16, 0).toDate();
String json = serializer.serialize(content.createdDate.eq(date));
assertThat(json).isEqualTo("{\"content.createdDate\":\"2015-05-01T14:00:00.000+0000\"}");
json = serializer.serialize(content.createdDate.lt(date));
assertThat(json).isEqualTo("{\"content.createdDate\":{\"$lt\":\"2015-05-01T14:00:00.000+0000\"}}");
}
@Test
public void should_serialize_predicate_with_in_operator() {
String json = serializer.serialize(content.packaging.in("a", "b", "c"));
assertThat(json).isEqualTo("{\"content.packaging\":{\"$in\":[\"a\",\"b\",\"c\"]}}");
}
@Test
public void should_serialize_predicate_with_not_in_operator() {
String json = serializer.serialize(content.quantity.notIn(10,100,99));
assertThat(json).isEqualTo("{\"content.quantity\":{\"$nin\":[10,100,99]}}");
}
}
package com.asis.kis.commons.util;
import java.util.Date;
import java.util.UUID;
import org.joda.time.DateTime;
import com.github.drapostolos.typeparser.TypeParser;
/**
* Permit to transform an a string or integer value into the specified type.
*
*/
public class JsonTypeConverter {
private TypeParser parser;
/**
* Default constructor of {@link JsonTypeConverter}
*/
public JsonTypeConverter() {
// create a TypeParser instance with default settings.
parser = TypeParser.newBuilder().build();
}
/**
* Convert the specified string into the specified type
*
* @param value the string value
* @param type expected type
* @return the converted object
*/
public <T> T convert(String value, Class<T> type) {
return doConvert(value, type);
}
/**
* Convert the specified integer into the specified type
*
* @param value the integer value
* @param type expected type
* @return the converted object
*/
public <T> T convert(Integer value, Class<T> type) {
return doConvert(value, type);
}
/**
* Convert the specified object into the specified type
*
* @param value the object value
* @param type expected type
* @return the converted object
*/
private <T> T doConvert(Object value, Class<T> type) {
// nothing to do - it is the good type
if (value.getClass().equals(type)) {
return (T) value;
}
// date converter
if (value instanceof String) {
if (type.equals(Date.class)) {
return (T) DateTime.parse((String) value).toDate();
} else if(type.equals(DateTime.class)) {
return (T) DateTime.parse((String) value);
}
else if(type.equals(UUID.class)) {
return (T) UUID.fromString(value.toString());
}
}
return parser.parse(value.toString(), type);
}
}
package com.asis.kis.persistence.core.querydsl;
import com.querydsl.core.types.Operator;
import com.querydsl.core.types.Ops;
/**
* This class represents all queryDSL operators and the associated Json operator.
* <p>
* It permits to link the json operator to the queryDSL operator.
*/
public enum QueryDslOperator {
EQ("$eq", Ops.EQ),
NE("$ne", Ops.NE),
LT("$lt", Ops.LT),
GT("$gt", Ops.GT),
LOE("$lte", Ops.LOE),
GOE("$gte", Ops.GOE),
LIKE("$like", Ops.LIKE),
STARTS_WITH("$start", Ops.STARTS_WITH),
ENDS_WITH("$end", Ops.ENDS_WITH),
AND("$and", Ops.AND),
OR("$or", Ops.OR),
BETWEEN("$between", Ops.BETWEEN),
IN("$in", Ops.IN),
NOT_IN("$nin", Ops.NOT_IN),
STRING_CONTAINS("$contains", Ops.STRING_CONTAINS);
/**
* the associated json operator
*/
private String json;
/**
* the associated queryDSL operator
*/
private Operator DSLOperator;
/**
* Default constructor of {@link QueryDslOperator}
*
* @param json the associated json operator
* @param DSLOperator the associated queryDSL operator
*/
QueryDslOperator(String json, Operator DSLOperator) {
this.json = json;
this.DSLOperator = DSLOperator;
}
/**
* Get the expression operator of the specified queryDSL operator
*
* @param op the queryDSL operator
* @return the expression operator
*/
public static QueryDslOperator getFromDsl(Operator op) {
for (QueryDslOperator queryDslOperator : QueryDslOperator.values()) {
if (queryDslOperator.getDSLOperator().equals(op)) {
return queryDslOperator;
}
}
throw new IllegalArgumentException("Illegal operator " + op);
}
/**
* get the expression operator from the json
*
* @param jsonValue the json value of the operator
* @return the expression operator
*/
public static QueryDslOperator getFromJson(String jsonValue) {
for (QueryDslOperator expressionOperator : QueryDslOperator.values()) {
if (expressionOperator.getJson().equals(jsonValue)) {
return expressionOperator;
}
}
throw new IllegalArgumentException("QueryDSL operator " + jsonValue + " unknown.");
}
public String getJson() {
return json;
}
public Operator getDSLOperator() {
return DSLOperator;
}
@Override
public String toString() {
return json;
}
}
@GitJoedg
Copy link

Hi, missing Jsons, SimpleStreams classes

@ysykzheng
Copy link

hello, new version querydsl not include class QueryDslDeserializer, which version you used?
<querydsl.version>4.4.0</querydsl.version>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment