codebot
codebot

Reputation: 2646

JPA criteria builder equal method is not working as expected

In my case I'm trying to fetch some data by extracting a value from a json column in db. My code is as follows,

criteriaBuilder.equal(criteriaBuilder.function("JSON_EXTRACT", Boolean.class, root.get("result"), criteriaBuilder.literal("$.matched")), false);

Above code gives me an empty set of data. Also this is working fine in query console.

But,

criteriaBuilder.between(criteriaBuilder.function("JSON_EXTRACT", Double.class, root.get("result"), criteriaBuilder.literal("$.streaming_threshold")), 0.1, 0.9);

this between method is working fine. What could be the mistake here?

UPDATE

Boolean values are the values that I couldn't read. NOT INTEGERS. My JSON structure,

{
    "status": "SUCCESS",
    "request_id": "request_id",
    "time_taken": 8454,
    "matched": false,
    "streaming_threshold": 0.5
}

Upvotes: 2

Views: 1863

Answers (2)

XIA YUN
XIA YUN

Reputation: 23

Default JPA convert boolean to 0/1, so if serialize boolean to 0/1 into database, the equal query will be ok.

Upvotes: 0

silentsudo
silentsudo

Reputation: 6963

I was not able to get it working with the raw boolean field. I converted the Boolean property on the object to String and vice-versa using @JsonSerialize and @JsonDeserialize and then persisted that as json and followed the same approach you did but now searching String.class as false instead of Boolean. My solution is as below:

Entity

@Entity
@Table(name = "json_container")
public class JsonContainer {

    @Id
    @GeneratedValue
    @Type(type = "uuid-char")
    private UUID id;

    @Column(columnDefinition = "json", name = "json_data")
    private String jsonData;

    public UUID getId() {
        return id;
    }

    public String getJsonData() {
        return jsonData;
    }

    public void setJsonData(String jsonData) {
        this.jsonData = jsonData;
    }

    public static class SampleDetails {
        private String status;
        private String requestId;
        private Integer timeTaken;
        @JsonSerialize(using = StringBooleanJsonSerializer.class)
        @JsonDeserialize(using = StringBooleanJsonDeserializer.class)
        private Boolean matched;
        private Double streamingThreshold;

        public SampleDetails() {
        }

        public SampleDetails(String status, String requestId, Integer timeTaken, Boolean matched, Double streamingThreshold) {
            this.status = status;
            this.requestId = requestId;
            this.timeTaken = timeTaken;
            this.matched = matched;
            this.streamingThreshold = streamingThreshold;
        }

        public String getStatus() {
            return status;
        }

        public String getRequestId() {
            return requestId;
        }

        public Integer getTimeTaken() {
            return timeTaken;
        }

        public Double getStreamingThreshold() {
            return streamingThreshold;
        }

        public Boolean getMatched() {
            return matched;
        }


        static class StringBooleanJsonSerializer extends JsonSerializer<Boolean> {

            @Override
            public void serialize(Boolean value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
                gen.writeString(value != null && value ? value.toString() : "false");
            }
        }

        static class StringBooleanJsonDeserializer extends JsonDeserializer<Boolean> {

            @Override
            public Boolean deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
                try {
                    return Boolean.parseBoolean(p.getText());
                } catch (RuntimeException e) {
                    return Boolean.FALSE;
                }
            }
        }
    }

Test Class

class MySQLJsonConverterTest {

    @Autowired
    private EntityManager entityManager;


    @Rollback(false)
    @Test
    void testCustomJsonConverter() throws JsonProcessingException {
        JsonContainer jsonContainer = new JsonContainer();
        jsonContainer.setJsonData(
                getAsJson(new JsonContainer.SampleDetails("success", "12344567", 8454, false, 0.1)));
        entityManager.persist(jsonContainer);
        Assertions.assertNotNull(jsonContainer.getId());

        jsonContainer = new JsonContainer();
        jsonContainer.setJsonData(
                getAsJson(new JsonContainer.SampleDetails("success", "8989", 121, true, 0.5)));
        entityManager.persist(jsonContainer);
        Assertions.assertNotNull(jsonContainer.getId());

        CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder();
        CriteriaQuery<JsonContainer> criteriaQuery = criteriaBuilder.createQuery(JsonContainer.class);
        Root<JsonContainer> from = criteriaQuery.from(JsonContainer.class);

        criteriaQuery.where(criteriaBuilder.equal(criteriaBuilder.function("JSON_EXTRACT", String.class, from.get("jsonData"),
                criteriaBuilder.literal("$.matched")), "false"));

        TypedQuery<JsonContainer> typedQuery = entityManager.createQuery(criteriaQuery);
        List<JsonContainer> resultList = typedQuery.getResultList();
        Assertions.assertEquals(1, resultList.size());
    }

    private String getAsJson(JsonContainer.SampleDetails sampleDetails) throws JsonProcessingException {
        //var created so debugging is ez
        String json = new ObjectMapper().writeValueAsString(sampleDetails);
        return json;
    }
}

Upvotes: 1

Related Questions