Skip to content

Store the Java type in the column for further introspection #423

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

Closed
djechelon opened this issue Dec 16, 2021 · 1 comment
Closed

Store the Java type in the column for further introspection #423

djechelon opened this issue Dec 16, 2021 · 1 comment

Comments

@djechelon
Copy link

This is a feature request impacting both SqlColumn<T> and the Mybatis generator.

I am working on a dynamic filter framework and I stumbled upon an obvious exception when working with dates.

I have the client sending a Short and I want to convert it (without too much hassle) in a java.time.Year.

@Data
public class SimpleFilter<T> {

    /**
     * Requires the property to be equal to the value
     */
    protected T eq;
    /**
     * Requires the property to be different from the value
     */
    protected T ne;
    /**
     * Requires the property to be any of the supplied values
     */
    protected T[] in;
    /**
     * Requires the property not to be any of the supplied values
     */
    protected T[] notIn;

    /**
     * Requires the property to be either not null or null.
     * The property can be used as:
     * <p>
     * - Unspecified: null check is ignored
     * - True: the property must be null
     * - False: the property must be not null
     */
    protected Boolean isNull;

}
  @Nullable
    @SuppressWarnings("unchecked")
    public <T> WhereApplier applyFilter(@Nullable WhereApplier whereApplier, SqlColumn<? super T> column, @Nullable SimpleFilter<T> propertyFilter) {
        if (propertyFilter == null)
            return whereApplier;

        if (propertyFilter.getEq() != null || (propertyFilter.getEq() instanceof String && isNotBlank((String) propertyFilter.getEq())))
            whereApplier = combineAnd(whereApplier, column, isEqualTo(propertyFilter.getEq()));
        if (propertyFilter.getNe() != null || (propertyFilter.getNe() instanceof String && isNotBlank((String) propertyFilter.getNe())))
            whereApplier = combineAnd(whereApplier, column, isNotEqualTo(propertyFilter.getEq()));
        if (propertyFilter.getIn() != null)
            whereApplier = combineAnd(whereApplier, column, isIn(propertyFilter.getIn()));
        if (propertyFilter.getNotIn() != null)
            whereApplier = combineAnd(whereApplier, column, isNotIn(propertyFilter.getNotIn()));
        if (propertyFilter.getIsNull() != null)
            whereApplier = combineAnd(whereApplier, column, propertyFilter.getIsNull() ? isNull() : isNotNull());

        if (propertyFilter instanceof SimpleComparableFilter)
            whereApplier = applyComparableFilter(whereApplier, (SqlColumn<? super Comparable<?>>) column, (SimpleComparableFilter) propertyFilter);


        return whereApplier;
    }

 /**
     * Static utility to combine WHERE predicates into AND expressions
     * <p>
     * Since there is a difference invoking method {@link org.mybatis.dynamic.sql.where.AbstractWhereDSL#where} vs
     * {@link org.mybatis.dynamic.sql.where.AbstractWhereDSL#and}, we must use <pre>where</pre> the first time, but
     * <pre>and</pre> the rest of the times.
     * <p>
     * This method checks if the argument is null
     * <p>
     * Trick: if you need additional overloads of <pre>where</pre>/<pre>and</pre> methods, you need to define additional
     * overloads of this method
     *
     * @param whereApplier
     * @param column
     * @param condition
     * @param <T>
     * @return
     */
    protected static <T> WhereApplier combineAnd(WhereApplier whereApplier, BindableColumn<T> column, VisitableCondition<T> condition) {
        if (whereApplier == null)
            return where -> where.where(column, condition);
        else return whereApplier.andThen(where -> where.and(column, condition));
    }

Basically I am cycling over the properties (each of type SimpleFilter<T>) and assign the value to the proper condition (equals, greater...).

The client sends me a number, such as 2021, so I would like, without much hassle, to convert it to a year.


java.lang.ClassCastException: class java.lang.Integer cannot be cast to class java.time.Year (java.lang.Integer and java.time.Year are in module java.base of loader 'bootstrap')
	at org.apache.ibatis.type.YearTypeHandler.setNonNullParameter(YearTypeHandler.java:28) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.type.BaseTypeHandler.setParameter(BaseTypeHandler.java:73) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.scripting.defaults.DefaultParameterHandler.setParameters(DefaultParameterHandler.java:87) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.statement.PreparedStatementHandler.parameterize(PreparedStatementHandler.java:94) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.statement.RoutingStatementHandler.parameterize(RoutingStatementHandler.java:64) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.SimpleExecutor.prepareStatement(SimpleExecutor.java:88) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.SimpleExecutor.doQuery(SimpleExecutor.java:62) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.BaseExecutor.queryFromDatabase(BaseExecutor.java:325) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.BaseExecutor.query(BaseExecutor.java:156) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:109) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.executor.CachingExecutor.query(CachingExecutor.java:89) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:151) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:145) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:140) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:76) ~[mybatis-3.5.7.jar:3.5.7]
	at jdk.internal.reflect.GeneratedMethodAccessor141.invoke(Unknown Source) ~[na:na]
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
	at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
	at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:427) ~[mybatis-spring-2.0.6.jar:2.0.6]
	at com.sun.proxy.$Proxy126.selectOne(Unknown Source) ~[na:na]
	at org.mybatis.spring.SqlSessionTemplate.selectOne(SqlSessionTemplate.java:160) ~[mybatis-spring-2.0.6.jar:2.0.6]
	at org.apache.ibatis.binding.MapperMethod.execute(MapperMethod.java:87) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.binding.MapperProxy$PlainMethodInvoker.invoke(MapperProxy.java:145) ~[mybatis-3.5.7.jar:3.5.7]
	at org.apache.ibatis.binding.MapperProxy.invoke(MapperProxy.java:86) ~[mybatis-3.5.7.jar:3.5.7]
	at com.sun.proxy.$Proxy178.count(Unknown Source) ~[na:na]
	at org.mybatis.dynamic.sql.util.mybatis3.MyBatis3Utils.countFrom(MyBatis3Utils.java:81) ~[mybatis-dynamic-sql-1.3.0.jar:1.3.0]
	at it.orbit.amlc.backend.data.mappers.VwPlanningAmlControlBaseMapper.count(VwPlanningAmlControlBaseMapper.java:106) ~[main/:na]

Request

To expose Class<T> getJavaType() in the SqlColumn<T> class. I will use such property to do some conversion, with the help of Spring's conversion service, before setting the dynamic value into the filter.

To amend the Mybatis generator to automatically add the Java type to the SqlColumn constructor in the helper class.

Porkaround

To do the conversion manually in a subclass YearFilter extends SimpleFilter<Year> as I already did with OffsetDateTime to LocalDateTime (whose conversion is simple)

Thanks for the attention

@jeffgbutler
Copy link
Member

This is already in the dynamic SQL library via this enhancement (not released yet): #386

Here is the corresponding issue in the generator: mybatis/generator#742

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

No branches or pull requests

2 participants