如何在mybatis的< arg>中将map正确设置为javatype?

68bkxrlz  于 2021-07-06  发布在  Java
关注(0)|答案(1)|浏览(320)

问题描述:

我有 java.lang.NoSuchMethodException: bar.Foo.<init>(java.lang.Long, java.lang.String, java.util.Map) 当我试图用mybatis从db中获取不可变的foo对象,却无法找出问题所在时:(
我有一个不成功的案例,用@value注解结果对象,用@data注解成功的案例(它们在下面相应的标题下)。所以,我想使用@value,但不要理解我做错了什么。。

失败案例:

所以,我有一个不可变的结果类:

@Value
public class Foo {
    long entryId;
    String description;
    Map<String, String> params;
}

它存储在postgres的foos表中, params 字段值以json格式存储在同一表的相应列中(类型为varchar,条目为 "{key=value}" 万一 params = Map.of("key", "value") . 我想从db中示例化这个类的对象,因此我使用以下mybatis代码:

<resultMap id="foo" type="bar.Foo">
     <constructor>
         <arg column="entry_id" javaType="java.lang.Long"/>
         <arg column="description" javaType="java.lang.String"/>
         <arg column="params" javaType="java.util.Map" jdbcType="VARCHAR" typeHandler="bar.MapToJsonStringHandler"/>
     </constructor>
</resultMap>

下面是我的类型处理程序(它已经在另一个案例中成功地使用了@data object而不是@value,所以我猜它本身是正确的):

public class MapToJsonStringHandler implements TypeHandler<Map<String, String>> {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @SneakyThrows(IOException.class)
    @Override
    public void setParameter(PreparedStatement ps, int i, Map<String, String> parameter, JdbcType jdbcType) throws SQLException {
        if (parameter == null) {
        ps.setNull(i, Types.VARCHAR);
    } else {
        ps.setString(i, objectMapper.writeValueAsString(parameter));
    }
}

@Override
public Map<String, String> getResult(ResultSet rs, String columnName) throws SQLException {
    String result = rs.getString(columnName);
    return convertToMap(result);
}

@Override
public Map<String, String> getResult(ResultSet rs, int columnIndex) throws SQLException {
    String result = rs.getString(columnIndex);
    return convertToMap(result);
}

@Override
public Map<String, String> getResult(CallableStatement cs, int columnIndex) throws SQLException {
    String result = cs.getString(columnIndex);
    return convertToMap(result);
}

@SneakyThrows(IOException.class)
private Map<String, String> convertToMap(String result) {
    return result == null ? Collections.emptyMap() : objectMapper.readValue(result, Map.class);
}

}
以下是sql:

<select id="getFoos" resultMap="foo">
     SELECT *
     FROM foos
     <![CDATA[WHERE needed_tm < now()]]>
</select>

当我拿到食物的时候 java.lang.NoSuchMethodException: bar.Foo.<init>(java.lang.Long, java.lang.String, java.util.Map) .
有趣的是,当我使用@data而不是@value时,它就像一个符咒:

成功案例:

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Foo {
    long entryId;
    String description;
    Map<String, String> params;
}

<resultMap id="foo" type="bar.Foo">
     <result column="entry_id" property="entryId"/>
     <result column="description" property="description"/>
     <result column="params" property="params" typeHandler="bar.MapToJsonStringHandler"/>
</resultMap>

sql和类型处理程序与不成功的情况相同。
请你给我一个提示,我可能遗漏了什么?提前谢谢!

更新1:

@Value
@AllArgsConstructor
public class Foo {
     long entryId;
     String description;
     Map<String, String> params;
}

给出了同样的例外。无论如何,据我所知,@value已经设计好了@allargsconstructor(https://projectlombok.org/features/value)

6yt4nkrj

6yt4nkrj1#

java.lang.nosuchmethodexception:bar.foo.(java.lang.long,java.lang.string,java.util.map)<---表示没有定义构造函数。
当您使用@allargsconstuctor时,您告诉lombok生成一个包含所有参数(long、string、map)的构造函数,这就是为什么它适合您的原因。
根据文件@数据:
@现在数据都在一起了:@tostring、@equalsandhashcode、@getter(所有字段)、setter(所有非最终字段)和@requiredargsconstructor的快捷方式
https://projectlombok.org/features/data
这就是为什么当您使用@data时,它会找到一个构造函数并且不会给您一个错误(nosuchmethod)。

<resultMap id="foo" type="bar.Foo">
     <constructor>
         <arg column="entry_id" javaType="java.lang.Long"/>
         <arg column="description" javaType="java.lang.String"/>
         <arg column="params" javaType="java.util.Map" jdbcType="VARCHAR" typeHandler="bar.MapToJsonStringHandler"/>
     </constructor>
</resultMap>

因为您将数据类型指定为java.lang.long,所以它希望构造函数被定义为具有该参数类型。
我相信@data并不是构造器帮了你,而是setters(拳击)帮了你很久。
尝试使用@value,并在你的类中从long改为long。看看这样行不行。
lombok将生成一个构造函数,使用(long,string,map),not(long,string,map)
很想知道你用的是什么java版本。

相关问题