perplexhub / rsql-jpa-specification

Java Library to Translate RSQL into Spring Data JPA Specification and QueryDSL Predicate
MIT License
223 stars 61 forks source link

rsql-querydsl failed to parse when type is Date #19

Closed BarrieShieh closed 4 years ago

BarrieShieh commented 4 years ago

Hi, When I use rsql-querydsl to parse the string for the query, I found the parser can not work properly The class I use is in the below. For String Boolean List Integer, it works fine. when comes to Date, If I use createdDate=='2020-03-16 05:00:47.584', It will generate empty query value.

BooleanExpression searchExp = RSQLQueryDslSupport.toPredicate(search, QUser.user);
Hibernate: 
    select
        user0_.uid as uid1_25_,
        user0_.created_by as created_2_25_,
        user0_.created_date as created_3_25_,
        user0_.last_modified_by as last_mod4_25_,
        user0_.last_modified_date as last_mod5_25_,
        user0_.username as username6_25_
    where
        user0_.created_date is null 
    order by
        user0_.created_date desc limit ?

When i use createdDate=lt='2020-03-16 05:00:47.584' , it will throw an exception

java.lang.NullPointerException: null
    at com.querydsl.core.types.ConstantImpl.<init>(ConstantImpl.java:124)
    at com.querydsl.core.types.ConstantImpl.create(ConstantImpl.java:108)
    at com.querydsl.core.types.dsl.ComparableExpression.lt(ComparableExpression.java:250)
    at io.github.perplexhub.rsql.RSQLQueryDslPredicateConverter.visit(RSQLQueryDslPredicateConverter.java:229)
    at io.github.perplexhub.rsql.RSQLQueryDslPredicateConverter.visit(RSQLQueryDslPredicateConverter.java:27)
    at cz.jirutka.rsql.parser.ast.ComparisonNode.accept(ComparisonNode.java:70)
    at io.github.perplexhub.rsql.RSQLQueryDslSupport.toPredicate(RSQLQueryDslSupport.java:37)
    at io.github.perplexhub.rsql.RSQLQueryDslSupport.toPredicate(RSQLQueryDslSupport.java:29)

The entity class I use:

@Data
@EntityListeners(AuditingEntityListener.class)
@JsonIgnoreProperties(value = {"hibernateLazyInitializer", "handler", "fieldHandler"})
public abstract class Audible<U> {
    @CreatedBy
    @Column(nullable = false, updatable = false)
    protected U createdBy;

    @CreatedDate
    @Temporal(TemporalType.TIMESTAMP)
    @Column(nullable = false, updatable = false, columnDefinition = "DATETIME(3)")
    protected Date createdDate;

    @LastModifiedBy
    protected U lastModifiedBy;

    @LastModifiedDate
    @Temporal(TemporalType.TIMESTAMP)
    @Column(columnDefinition = "DATETIME(3)")
    protected Date lastModifiedDate;
}
@Entity
@Data
@Builder(toBuilder = true)
@NoArgsConstructor
@AllArgsConstructor
@Slf4j
@EqualsAndHashCode(callSuper = true)
@Table(name = "sys_user", uniqueConstraints = {@UniqueConstraint(columnNames = {"uid"})})
@JsonView(View.Public.class)
public class User extends Audible<String> implements BaseEntity {
    @Id
    @GeneratedValue(generator = "uuid2")
    @GenericGenerator(name = "uuid2", strategy = "uuid2")
    @Column()
    private String uid;

    @Column(unique = true, nullable = false)
    private String username;

    @JsonSerialize(using = PasswordJsonSerializer.class)
    @Column(nullable = false)
    private String password;

    private String firstName;

    private String lastName;

    private String eMail;

    @ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.REFRESH})
    @JoinTable(
            name = "sys_user_role_mapping",
            joinColumns = {@JoinColumn(name = "userId", referencedColumnName = "uid")},
            inverseJoinColumns = {@JoinColumn(name = "roleId", referencedColumnName = "uid")}
    )
    @JsonView(View.ExtendedPublic.class)
    private List<Role> roles;

    @Column(nullable = false)
    private Boolean enabled = true;
}
perplexhub commented 4 years ago
  1. Try update to 5.0.3.
  2. Add below to your config class
    @Bean
    public Object rsqlConfiguration(RSQLCommonSupport rsqlCommonSupport) {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        RSQLCommonSupport.addConverter(Date.class, s -> {
            try {
                return sdf.parse(s);
            } catch (Exception e) {
                return null;
            }
        });
        return rsqlCommonSupport;
    }

I've create a test case for your reference, please refer to io.github.perplexhub.rsql.RSQLQueryDslSupportTest.testBetweenDateTime()

BarrieShieh commented 4 years ago

It works, thanks for replying.