RSQL-Parser和布尔查询值导致IllegalArgumentException错误。

huangapple go评论115阅读模式
英文:

RSQL-Parser and boolean query values failing with IllegalArgumentException

问题

我有一个 REST API,我使用 RSQL 解析器实现了查询功能。它对一切都很有效,但布尔值 "true" 和 "false" 除外。

以下是我 RSQL 规范,根据 Baeldung 的示例稍作修改以处理 API 中的枚举值:

  1. public class GenericRsqlSpecification<T> implements Specification<T> {
  2. private String property;
  3. private ComparisonOperator operator;
  4. private List<String> arguments;
  5. public GenericRsqlSpecification(String property, ComparisonOperator operator, List<String> arguments) {
  6. this.property = property;
  7. this.operator = operator;
  8. this.arguments = arguments;
  9. }
  10. @Override
  11. public Predicate toPredicate(Root<T> root, CriteriaQuery<?> query, CriteriaBuilder builder) {
  12. // ... (代码在此省略)
  13. }
  14. // ... (代码在此省略)
  15. }

关于 Car 模型的部分如下:

  1. public class CarDO {
  2. @Id
  3. @GeneratedValue(strategy = GenerationType.IDENTITY)
  4. private Long id;
  5. @Column(nullable = false)
  6. @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
  7. private ZonedDateTime dateCreated = ZonedDateTime.now();
  8. @Column(nullable = false)
  9. private String licensePlate;
  10. @Column(nullable = false)
  11. private int seatCount;
  12. @Column(nullable = false)
  13. private boolean convertible;
  14. @Column(nullable = false)
  15. private int rating;
  16. @Column(nullable = false)
  17. @Enumerated(EnumType.STRING)
  18. private EngineType engineType;
  19. @Column(nullable = false)
  20. private String manufacturer;
  21. @Column(nullable = false)
  22. private boolean selected;
  23. @OneToOne(fetch = FetchType.EAGER)
  24. @JoinTable(name = "driver_with_car",
  25. joinColumns = {@JoinColumn(name = "car_id")},
  26. inverseJoinColumns = {@JoinColumn(name = "driver_id")})
  27. private DriverDO driver;
  28. //Constructors, Getters and Setters not included.
  29. }

目前,对这个问题不太确定如何解决。目前,搜索只会引发以下异常:

  1. java.lang.IllegalArgumentException: Parameter value [true] did not match expected type [java.lang.Boolean (n/a)]

有关其余代码的 Github 存储库链接请参见 car-booking-system

英文:

I have a rest API which I have implemented a query feature using RSQL-Parser. It works great for everything but boolean values "true" & "false".
This is my Rsql Specification following examples from Baeldung with some minor alterations to deal with Enum values have in the API.

  1. public class GenericRsqlSpecification&lt;T&gt; implements Specification&lt;T&gt; {
  2. private String property;
  3. private ComparisonOperator operator;
  4. private List&lt;String&gt; arguments;
  5. public GenericRsqlSpecification(String property, ComparisonOperator operator, List&lt;String&gt; arguments) {
  6. this.property = property;
  7. this.operator = operator;
  8. this.arguments = arguments;
  9. }
  10. @Override
  11. public Predicate toPredicate(Root&lt;T&gt; root, CriteriaQuery&lt;?&gt; query,
  12. CriteriaBuilder builder) {
  13. Path&lt;String&gt; propertyExpression = parseProperty(root);
  14. List&lt;Object&gt; args = castArguments(propertyExpression);
  15. Object argument = args.get(0);
  16. switch (RsqlSearchOperation.getSimpleOperator(operator)) {
  17. case EQUAL:
  18. if (argument instanceof String)
  19. return builder.like(propertyExpression,
  20. argument.toString().replace(&#39;*&#39;, &#39;%&#39;));
  21. else if (argument == null)
  22. return builder.isNull(propertyExpression);
  23. else return builder.equal(propertyExpression, argument);
  24. case NOT_EQUAL:
  25. if (argument instanceof String)
  26. return builder.notLike(propertyExpression,
  27. argument.toString().replace(&#39;*&#39;, &#39;%&#39;));
  28. else if (argument == null)
  29. return builder.isNotNull(propertyExpression);
  30. else return builder.notEqual(propertyExpression, argument);
  31. case GREATER_THAN:
  32. return builder.greaterThan(propertyExpression,
  33. argument.toString());
  34. case GREATER_THAN_OR_EQUAL:
  35. return builder.greaterThanOrEqualTo(propertyExpression,
  36. argument.toString());
  37. case LESS_THAN:
  38. return builder.lessThan(propertyExpression,
  39. argument.toString());
  40. case LESS_THAN_OR_EQUAL:
  41. return builder.lessThanOrEqualTo(propertyExpression,
  42. argument.toString());
  43. case IN:
  44. return propertyExpression.in(args);
  45. case NOT_IN:
  46. return builder.not(propertyExpression.in(args));
  47. }
  48. return null;
  49. }
  50. private Path&lt;String&gt; parseProperty(Root&lt;T&gt; root) {
  51. Path&lt;String&gt; path;
  52. if (property.contains(&quot;.&quot;)) {
  53. // Nested properties
  54. String[] pathSteps = property.split(&quot;\\.&quot;);
  55. String step = pathSteps[0];
  56. path = root.get(step);
  57. From lastFrom = root;
  58. for (int i = 1; i &lt;= pathSteps.length - 1; i++) {
  59. if (path instanceof PluralAttributePath) {
  60. PluralAttribute attr = ((PluralAttributePath) path).getAttribute();
  61. Join join = getJoin(attr, lastFrom);
  62. path = join.get(pathSteps[i]);
  63. lastFrom = join;
  64. } else if (path instanceof SingularAttributePath) {
  65. SingularAttribute attr = ((SingularAttributePath) path).getAttribute();
  66. if (attr.getPersistentAttributeType() != Attribute.PersistentAttributeType.BASIC) {
  67. Join join = lastFrom.join(attr, JoinType.LEFT);
  68. path = join.get(pathSteps[i]);
  69. lastFrom = join;
  70. } else {
  71. path = path.get(pathSteps[i]);
  72. }
  73. } else {
  74. path = path.get(pathSteps[i]);
  75. }
  76. }
  77. } else {
  78. path = root.get(property);
  79. }
  80. return path;
  81. }
  82. private Join getJoin(PluralAttribute attr, From from) {
  83. switch (attr.getCollectionType()) {
  84. case COLLECTION:
  85. return from.join((CollectionAttribute) attr);
  86. case SET:
  87. return from.join((SetAttribute) attr);
  88. case LIST:
  89. return from.join((ListAttribute) attr);
  90. case MAP:
  91. return from.join((MapAttribute) attr);
  92. default:
  93. return null;
  94. }
  95. }
  96. private List&lt;Object&gt; castArguments(Path&lt;?&gt; propertyExpression) {
  97. Class&lt;?&gt; type = propertyExpression.getJavaType();
  98. return arguments.stream().map(arg -&gt; {
  99. if (type.equals(Integer.class)) return Integer.parseInt(arg);
  100. else if (type.equals(Long.class)) return Long.parseLong(arg);
  101. else if (type.equals(Byte.class)) return Byte.parseByte(arg);
  102. else if (type.equals(Boolean.class)) return Boolean.parseBoolean(arg);
  103. else if (type.equals(EngineType.class)) return EngineType.valueOf(arg);
  104. else if (type.equals(OnlineStatus.class)) return OnlineStatus.valueOf(arg);
  105. else return arg;
  106. }).collect(Collectors.toList());
  107. }
  108. //GETTERS &amp; SETTERS left out.
  109. }

Car Model

  1. public class CarDO {
  2. @Id
  3. @GeneratedValue(strategy = GenerationType.IDENTITY)
  4. private Long id;
  5. @Column(nullable = false)
  6. @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
  7. private ZonedDateTime dateCreated = ZonedDateTime.now();
  8. @Column(nullable = false)
  9. private String licensePlate;
  10. @Column(nullable = false)
  11. private int seatCount;
  12. @Column(nullable = false)
  13. private boolean convertible;
  14. @Column(nullable = false)
  15. private int rating;
  16. @Column(nullable = false)
  17. @Enumerated(EnumType.STRING)
  18. private EngineType engineType;
  19. @Column(nullable = false)
  20. private String manufacturer;
  21. @Column(nullable = false)
  22. private boolean selected;
  23. @OneToOne(fetch = FetchType.EAGER)
  24. @JoinTable(name = &quot;driver_with_car&quot;,
  25. joinColumns = {@JoinColumn(name = &quot;car_id&quot;)},
  26. inverseJoinColumns = {@JoinColumn(name = &quot;driver_id&quot;)})
  27. private DriverDO driver;
  28. //Constructors, Getters and Setters not included.
  29. }

Not really sure on how to work around this issue. Currently, the search just fails with this exception

  1. java.lang.IllegalArgumentException: Parameter value [true] did not match expected type [java.lang.Boolean (n/a)]

Github repo for rest of the code
car-booking-system

答案1

得分: 1

在一个“这不可能是这样,但是算了” 的瞬间,我将可转换和选择的数据类型从boolean更改为Boolean,然后一切正常运作。

  1. public class CarDO {
  2. @Id
  3. @GeneratedValue(strategy = GenerationType.IDENTITY)
  4. private Long id;
  5. @Column(nullable = false)
  6. @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
  7. private ZonedDateTime dateCreated = ZonedDateTime.now();
  8. @Column(nullable = false)
  9. private String licensePlate;
  10. @Column(nullable = false)
  11. private int seatCount;
  12. @Column(nullable = false)
  13. private Boolean convertible;
  14. @Column(nullable = false)
  15. private int rating;
  16. @Column(nullable = false)
  17. @Enumerated(EnumType.STRING)
  18. private EngineType engineType;
  19. @Column(nullable = false)
  20. private String manufacturer;
  21. @Column(nullable = false)
  22. private Boolean selected;
  23. @OneToOne(fetch = FetchType.EAGER)
  24. @JoinTable(name = "driver_with_car",
  25. joinColumns = {@JoinColumn(name = "car_id")},
  26. inverseJoinColumns = {@JoinColumn(name = "driver_id")})
  27. private DriverDO driver;
  28. }
英文:

So on a "That can't be it but what the heck" moment I changed the datatype of convertible and selected to Boolean instead of boolean and all worked fine.

  1. public class CarDO {
  2. @Id
  3. @GeneratedValue(strategy = GenerationType.IDENTITY)
  4. private Long id;
  5. @Column(nullable = false)
  6. @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
  7. private ZonedDateTime dateCreated = ZonedDateTime.now();
  8. @Column(nullable = false)
  9. private String licensePlate;
  10. @Column(nullable = false)
  11. private int seatCount;
  12. @Column(nullable = false)
  13. private Boolean convertible;
  14. @Column(nullable = false)
  15. private int rating;
  16. @Column(nullable = false)
  17. @Enumerated(EnumType.STRING)
  18. private EngineType engineType;
  19. @Column(nullable = false)
  20. private String manufacturer;
  21. @Column(nullable = false)
  22. private Boolean selected;
  23. @OneToOne(fetch = FetchType.EAGER)
  24. @JoinTable(name = &quot;driver_with_car&quot;,
  25. joinColumns = {@JoinColumn(name = &quot;car_id&quot;)},
  26. inverseJoinColumns = {@JoinColumn(name = &quot;driver_id&quot;)})
  27. private DriverDO driver;

huangapple
  • 本文由 发表于 2020年10月8日 22:04:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/64264235.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定