简体   繁体   中英

MyBatis: Boolean Parameter: MyBatis is using Getter

Subject: MyBatis: Boolean Paraeter: MyBatis is using Getter

Content:

Hello everyone,

I have been searching for a while for a solution to my nearly-simple MyBatis problem:


Given code (only the necessary parts):

mybatis-config.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
    <typeAliases>
        <!-- Model types. -->
        <typeAlias type="com.blockhaus2000.bh2k.portal.data.model.Navigation" alias="Navigation" />
        <!-- ... more types ... --->
    </typeAliases>
    <mappers>
        <mapper resource="mapper/NavigationDAO.xml" />
        <!-- ... more mappers ... -->
    </mappers>
</configuration>

NavigationDAO.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.blockhaus2000.bh2k.portal.data.dao.NavigationDAO">
    <resultMap type="Navigation" id="navigationResultMap">
        <id property="id" column="navigationId" />
        <result property="title" column="navigationTitle" />
        <result property="order" column="navigationOrder" />
        <result property="visible" column="navigationVisible" />
        <discriminator javaType="String" column="resolve">
            <case value="yes" resultMap="enhancedNavigationResultMap" />
        </discriminator>
    </resultMap>
    <resultMap type="Navigation" id="enhancedNavigationResultMap" extends="navigationResultMap">
        <collection property="navigationEntries" ofType="NavigationEntry">
            <id property="navigationId" column="navigationId" />
            <id property="pageId" column="pageId" />
            <result property="title" column="navigationEntryTitle" />
            <result property="order" column="navigationEntryOrder" />
            <result property="visible" column="navigationEntryVisible" />
        </collection>
    </resultMap>

    <!-- Methods from BaseDAO. -->
    <insert id="insert" parameterType="Navigation" useGeneratedKeys="true" keyProperty="id" keyColumn="navigationId">
        <!-- SQL -->
    </insert>
    <insert id="save" parameterType="Navigation">
        <!-- SQL -->
    </insert>
    <delete id="delete" parameterType="Navigation">
        <!-- SQL -->
    </delete>
    <select id="exists" parameterType="Navigation" resultType="boolean">
        <!-- SQL -->
    </select>

    <!-- Methods from UpdateableDAO. -->
    <update id="update" parameterType="Navigation">
        <!-- SQL -->
    </update>

    <!-- Methods from NavigationDAO. -->
    <select id="findVisibleNavigations" parameterType="boolean" resultMap="navigationResultMap">
        SELECT
            N.navigationId,
            N.navigationTitle,
            N.navigationOrder,
            N.navigationVisible,
        <if test="resolve">
            NE.pageId,
            NE.navigationEntryTitle,
            NE.NavigationEntryOrder,
            NE.navigationEntryVisible,
        </if>
            IF (
                #{resolve} = 'true',
                'yes',
                'no'
            ) AS resolve
        FROM
            Navigation AS N
        <if test="resolve">
        INNER JOIN NavigationEntry AS NE ON N.navigationId = NE.navigationId
        </if>
        WHERE
            N.navigationVisible = TRUE
        <if test="resolve">
            AND
            NE.navigationEntryVisible = TRUE
            AND
            NE.navigationEntryTitle IS NOT NULL
        </if>
    </select>
    <select id="findHiddenNavigations" parameterType="boolean" resultMap="navigationResultMap">
        <!-- SQL -->
    </select>
    <select id="findNavigation" parameterType="Map" resultMap="navigationResultMap">
        <!-- SQL -->
    </select>
</mapper>

NavigationDAO.java:

package com.blockhaus2000.bh2k.portal.data.dao;

import java.util.SortedSet;

import com.blockhaus2000.bh2k.portal.data.model.Navigation;

public interface NavigationDAO extends BaseDAO<Navigation>, UpdateableDAO<Navigation> {
    SortedSet<Navigation> findVisibleNavigations(final boolean resolve);

    SortedSet<Navigation> findHiddenNavigations(final boolean resolve);

    Navigation findNavigation(final int id, final boolean resolve);
}

BaseDAO.java:

package com.blockhaus2000.bh2k.portal.data.dao;

import com.blockhaus2000.bh2k.portal.data.model.BaseModel;

public interface BaseDAO<T extends BaseModel<T>> {
    int insert(final T obj);

    int save(final T obj);

    int delete(final T obj);

    boolean exists(final T obj);
}

UpdateableDAO.java:

package com.blockhaus2000.bh2k.portal.data.dao;

import com.blockhaus2000.bh2k.portal.data.model.BaseModel;

public interface UpdateableDAO<T extends BaseModel<T>> extends BaseDAO<T> {
    int update(final T obj);
}

Everything is starting correctly, but on an invocation of

NavigationDAO.findVisibleNavigations(true) // Or false.

the following Exception is thrown:

org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'resolve' in 'class java.lang.Boolean'
    at org.mybatis.(...)
    at org.apache.ibatis.(...)
    at com.blockhaus2000.bh2k.portal.data.test.NavigationDAOSpec.test findVisibleNavigations(NavigationDAOSpec.groovy:224)
Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'resolve' in 'class java.lang.Boolean'
    at org.apache.ibatis.(...)
    at org.mybatis.(...)
    ... 5 more

That said, the solution may be to change the "parameterType" to "Map" and replacing "resolve" with "param1". But that does not work either. Also, if I remove the

<if test="..."> ... </if>

it does execute correctly (except for the functionaility, of course).


I am happy about every single answer.

Thanks for your help Fabian


Edit 1 :

Here is my data model for "Navigation":

package com.blockhaus2000.bh2k.portal.data.model;

import java.util.SortedSet;

public class Navigation implements BaseModel<Navigation>, Comparable<Navigation> {
    private static final long serialVersionUID = 4019792023891297733L;

    /**
     * <p>
     * <b> PRIMARY KEY </b>
     * <br>
     * <b> AUTO_INCREMENT </b>
     * </p>
     */
    private int id = -1;
    private String title;
    private int order;
    private boolean visible;

    // ~ non-persistent fields ~

    private transient SortedSet<NavigationEntry> navigationEntries;

    // compateTo()
    // toString()
    // hashCode()
    // equals(Object)

    public int getId() {
        return this.id;
    }

    public String getTitle() {
        return this.title;
    }

    public int getOrder() {
        return this.order;
    }

    public boolean isVisible() {
        return this.visible;
    }

    public SortedSet<NavigationEntry> getNavigationEntries() {
        return this.navigationEntries;
    }

    public Navigation setId(final int id) {
        this.id = id;

        return this;
    }

    public Navigation setTitle(final String title) {
        this.title = title;

        return this;
    }

    public Navigation setOrder(final int order) {
        this.order = order;

        return this;
    }

    public Navigation setVisible(final boolean visible) {
        this.visible = visible;

        return this;
    }

    public Navigation setNavigationEntries(final SortedSet<NavigationEntry> navigationEntries) {
        this.navigationEntries = navigationEntries;

        return this;
    }
}

I forgot to explain what "resolve" does: It is a simple boolean identifying whether to load the transient properties or not.

In your sample MyBatis tries to call getResolve() on the boolean parameter (which obviously cannot work) because the name of the formal parameter in your Java method declaration is not used all, so your "resolve" in xml does not match the parameter name "resolve".

To give your parameter the MyBatis name resolve choose parameterType="map" in your NavigationDAO.xml:

...
<select id="findVisibleNavigations" parameterType="map" resultMap="navigationResultMap">
...
<select id="findHiddenNavigations" parameterType="map" resultMap="navigationResultMap">

And annotate your parameter in NavigationDAO.java with @Param("resolve") , maybe you have to remove final, but I don't know that for sure:

....
SortedSet<Navigation> findVisibleNavigations(@Param("resolve") final boolean resolve);
SortedSet<Navigation> findHiddenNavigations(@Param("resolve") final boolean resolve);
...

Update 1:

According to this description you might leave parameterType at all but I have never used that.

You should merely remove the parameterType="boolean" from the select statement. Then Mybatis will use actual boolean value for parameter #{resolve} (or what ever the name). Specifying parameterType forces Mybatis to look up a resolve property into parameter. It is actually only required for complex types.

Alternatively naming parameter by using annotation @Param("resolve") in mapper interface will also do the work.

您可以将#{resolve}补充为#{1},或使用注释@Param(“ resolve”)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM