Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feature Request] - Add information about AbstractScalarProvider for working with JSON to the documentation #894

Open
storympro opened this issue Jan 20, 2025 · 2 comments
Labels
enhancement New feature or request

Comments

@storympro
Copy link

storympro commented Jan 20, 2025

Reason

I couldn't find an explanation for working with jsonb to make the custom field type work correctly.

https://babyfish-ct.github.io/jimmer-doc/docs/configuration/scala-provider

Description

I have custom type:

import com.fasterxml.jackson.annotation.JsonValue;

import java.io.Serializable;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public class Translation implements Serializable {
    private final Map<String, String> translation;

    public Translation() {
        this.translation = new HashMap<>();
    }

    public Translation(Map<String, String> translation) {
        this.translation = new HashMap<>(translation);
    }

    public Translation set(String lang, String value) {
        this.translation.put(lang, value);
        return this;
    }

    public String get(String lang) {
        return this.translation.get(lang);
    }

    @JsonValue
    public Map<String, String> get() {
        return Collections.unmodifiableMap(this.translation);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Translation that = (Translation) o;
        return Objects.equals(translation, that.translation);
    }

    @Override
    public int hashCode() {
        return Objects.hash(translation);
    }

    @Override
    public String toString() {
        return "Translation{" +
                "translation=" + translation +
                '}';
    }
}

Implemented and working AbstractScalarProvider

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.babyfish.jimmer.sql.runtime.AbstractScalarProvider;
import org.springframework.stereotype.Component;

@Component
public class TranslationScalarProvider extends AbstractScalarProvider<Translation, String> {
    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Translation toScalar(String sqlValue) throws JsonProcessingException {
        if (sqlValue.isEmpty()) {
            return new Translation();
        }

        return new Translation(objectMapper.readValue(sqlValue, new TypeReference<>() {
        }));
    }

    @Override
    public String toSql(Translation scalarValue) throws JsonProcessingException {
        return objectMapper.writeValueAsString(scalarValue.get());
    }

    @Override
    public boolean isJsonScalar() { ///////////////////////// IS REQUIRED
        return true;                           ///////////////////////// NEED TRUE
    }
}

My entity

@Entity
public interface Example {

    /**
     * Назва
     */
    @Nonnull
    //@Serialized ///////////////////////// REMOVE IT
    Translation name();

    /**
     * Опис
     */
    @Nonnull
    //@Serialized ///////////////////////// REMOVE IT
    Translation description();
}

If you leave @serialized , then in the absence of isJsonScalar() it will return a value, but there will be an error when inserting the field.

Existing solutions

No response

@storympro storympro added the enhancement New feature or request label Jan 20, 2025
@babyfish-ct
Copy link
Owner

there will be an error when inserting the field.

Stacktrace please

@storympro
Copy link
Author

there will be an error when inserting the field.

Stacktrace please

if I added @ Serialized. The name and description are empty, but the values ​​are present in the database. Insertion still works. "isJsonScalar" is ignored
Image

Image
<===Execute SQL
2025-01-21T07:03:46.787+02:00 INFO 7284 --- [nio-8080-exec-2] o.b.jimmer.sql.runtime.ExecutorForLog : Execute SQL===>
Purpose: MUTATE
SQL: insert into websites_templates(created_at, updated_at, NAME, DESCRIPTION, STATUS, id_website) values(? /* 2025-01-21 07:03:46.7720742 /, ? / 2025-01-21 07:03:46.7720742 /, ? / {"uk":"тест"} /, ? / {"uk":""} /, ? / 0 /, ? / 6 */) returning ID
Affected row count: 1
JDBC response status: success
Time cost: 6ms
<===Execute SQL

But if you don't specify isJsonScalar and Seialized, there will be an error when inserting
org.postgresql.util.PSQLException: ERROR: column "name" is of type jsonb and expression is character varying
Hint: You will need to rewrite or quote the expression.
Position: 110

Caused by: org.babyfish.jimmer.sql.exception.ExecutionException: Cannot execute the DDL statement
at org.babyfish.jimmer.sql.ast.impl.mutation.Operator.lambda$executeAndGetRowCountsOneByOne$1(Operator.java:708)
at org.babyfish.jimmer.sql.runtime.DefaultExecutor.execute(DefaultExecutor.java:60)
at org.babyfish.jimmer.sql.runtime.ExecutorForLog.prettyLog(ExecutorForLog.java:125)
at org.babyfish.jimmer.sql.runtime.ExecutorForLog.execute(ExecutorForLog.java:45)
at org.babyfish.jimmer.sql.ast.impl.mutation.Operator.executeAndGetRowCountsOneByOne(Operator.java:676)
at org.babyfish.jimmer.sql.ast.impl.mutation.Operator.executeAndGetRowCounts(Operator.java:609)
at org.babyfish.jimmer.sql.ast.impl.mutation.Operator.execute(Operator.java:857)
at org.babyfish.jimmer.sql.ast.impl.mutation.Operator.insert(Operator.java:190)
at org.babyfish.jimmer.sql.ast.impl.mutation.Saver.saveSelf(Saver.java:207)
at org.babyfish.jimmer.sql.ast.impl.mutation.Saver.saveAllImpl(Saver.java:106)
at org.babyfish.jimmer.sql.ast.impl.mutation.Saver.lambda$save$0(Saver.java:48)
at org.babyfish.jimmer.runtime.Internal.modifyDraft(Internal.java:173)
at org.babyfish.jimmer.runtime.Internal.lambda$produce$1(Internal.java:42)
at org.babyfish.jimmer.runtime.Internal.usingDraftContext(Internal.java:102)
at org.babyfish.jimmer.runtime.Internal.produce(Internal.java:39)
at org.babyfish.jimmer.sql.ast.impl.mutation.Saver.save(Saver.java:44)
at org.babyfish.jimmer.sql.ast.impl.mutation.SimpleEntitySaveCommandImpl.executeImpl(SimpleEntitySaveCommandImpl.java:47)
at org.babyfish.jimmer.spring.cfg.support.SpringConnectionManager.execute(SpringConnectionManager.java:31)
at org.babyfish.jimmer.sql.ast.impl.mutation.SimpleEntitySaveCommandImpl.execute(SimpleEntitySaveCommandImpl.java:39)
at org.babyfish.jimmer.sql.ast.impl.mutation.SimpleEntitySaveCommandImpl.execute(SimpleEntitySaveCommandImpl.java:18)
at org.babyfish.jimmer.sql.ast.Executable.execute(Executable.java:12)
at org.babyfish.jimmer.sql.Saver.insert(Saver.java:305)
at org.babyfish.jimmer.sql.di.AbstractJSqlClientDelegate.insert(AbstractJSqlClientDelegate.java:225)
at ....TemplateService.insert(TemplateService.java:105)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103)
at java.base/java.lang.reflect.Method.invoke(Method.java:580)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:359)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:196)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:163)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:380)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:727)
at .....TemplateService$$SpringCGLIB$$0.insert()
... 131 more
Caused by: org.postgresql.util.PSQLException: ПОМИЛКА: стовпець "name" має тип jsonb, а вираз character varying
Hint: Потрібно буде переписати або привести вираз.
Position: 110
at org.postgresql.core.v3.QueryExecutorImpl.receiveErrorResponse(QueryExecutorImpl.java:2733)
at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:2420)
at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:372)
at org.postgresql.jdbc.PgStatement.executeInternal(PgStatement.java:517)
at org.postgresql.jdbc.PgStatement.execute(PgStatement.java:434)
at org.postgresql.jdbc.PgPreparedStatement.executeWithFlags(PgPreparedStatement.java:194)
at org.postgresql.jdbc.PgPreparedStatement.executeUpdate(PgPreparedStatement.java:155)
at com.zaxxer.hikari.pool.ProxyPreparedStatement.executeUpdate(ProxyPreparedStatement.java:61)
at com.zaxxer.hikari.pool.HikariProxyPreparedStatement.executeUpdate(HikariProxyPreparedStatement.java)
at org.babyfish.jimmer.sql.ast.impl.mutation.Operator.lambda$executeAndGetRowCountsOneByOne$1(Operator.java:696)
... 166 more

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants