"Type class is not known to the MapperRegistry" in MyBatis - mybatis

My Problem
I'm getting the error Type class myPackage.MyClass is not known to the MapperRegistry.
I successfully acquired a session, and upon debugging I can see that it otherwise appears to be configured correctly so the interface association seems to be working; therefor I'm confident this error is distinct from the stack-overflow-suggested Type interface is not known... question.
I'm new to myBatis but from the documentation I understood that the following was all that was required to get resultType auto-mapping to work.
Update: This also happens when mapping the mapper resources by xml file instead of by class.
My Mapper
public interface MyClassMapper{
MyClass getMyClass(Integer id);
}
My Model
public class MyClass{
private String itemValue;
public String getItemValue() {
return itemValue;
}
public void setItemValue(String itemValue) {
this.itemValue = itemValue;
}
}
My Sql Map
<?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="myPackage.orm.sqlMap.MyClassMapper" >
<select id="getMyClass" resultType="myPackage.MyClass" >
select itemValue
from SOME_TABLE
WHERE id = #{id}
</select>
</mapper>
My mybatis-config.xml
...
<mappers>
<mapper class="myPackage.MyClass" />
</mappers>
...

Fixed:
public MyClass getMyClassValue(Integer id) throws Exception{
SqlSession session = MyBatisSessionFactory.openSession();
MyClassMapper mapper = (MyClassMapper) session.getMapper(MyClass.class);
return mapper.getMyClass(id);
}
Here is the code I was using to execute the query, discovered that I was looking up the mapper in the mapper registry by the model class name, rather than the mapper interface name. Works just fine now.

In your mapper.xml file mapper's namespace should be the path to the mapper interface.
for example:
<mapper namespace="com.mapper.LineMapper">
<select id="selectLine" resultType="com.jiaotong114.jiaotong.beans.Line">
select * from bus_line where id = #{id}
</select>
</mapper>
your mapper interface should be in com.mapper package and the name of it is LineMapper.
hope help.

I solved this issue by adding the mapper XML to the mybatis xml configuration file
<mappers>
<mapper resource="com/java/Mapper.xml"/>
</mappers>

Related

Use an property of an object which is array of strings in mapper XML

I want to refer to a property in an object in my mapper file which is an array of strings in a SQL IN criteria. The query does a count, so all it needs to return is a numeric value. The query needs to adjust its count based on a flexible set of criteria defined in a filter object. Some filters will be present (ie. not null), and others will be absent.
<?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="TotalUniqueUsers">
<select id="getTotalUniqueUsers"
resultType="int"
parameterType="RequestFilter">
SELECT *
FROM MY_TABLE
WHERE
<if test="quarterList!=null and quarterList.length>0">
AND trim(FISCAL_QUARTER_NAME) IN #{quarterList javaType=list}
</if>
</select>
</mapper>
public class RequestFilter {
private String[] quarterList;
public String[] getQuarterList(){
return this.quarterList;
}
public void setQuarterList(String[] quarterList){
this.quarterList=quarterList;
}
}
Note, there is no type handler for RequestFilter. I did not think I needed one. I'm not trying to take an object and condense it into say one field in some weird way. All I want to do is have an input parameter to the
With the above, I get
org.apache.ibatis.exceptions.PersistenceException:
...
Caused by: org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'quarterList javaType=list' in 'class RequestFilter'
I tried javaType=Array also, but get the same result. If I change the
#{quarterList javaType=list}
to
#{quarterList}
it says the typeHandler is null for the RequestFilter.
There is no portable way to set the list or array to IN prepared statement parameter in JDBC and therefore in mybatis (there are ways to do that if you are using postgres).
So in the general case you need to dynamically generate the query with a parameter per element in the list:
<select id="getTotalUniqueUsers"
resultType="int"
parameterType="RequestFilter">
SELECT *
FROM MY_TABLE
WHERE
<if test="quarterList!=null and quarterList.length>0">
trim(FISCAL_QUARTER_NAME) IN (
<foreach item='quarter' collection='quarterList' separator=','>
#{quarter}
</foreach>
)
</if>
</select>

where can Mybatis get #{id} when I use statement of "DELETE FROM table WHERE id = #{id}"

<mapper namespace = "com.my">
<delete id="deleteById">
DELETE FROM table
WHERE id = #{id}
</delete>
</mapper>
Code above.
Where does Mybatis get the value of #{id},must I code a resultMap in the namespace?
I am not sure what is com.my Assuming there is class named MyClass under package com.my
On your DAO I believe you have use something like
session.delete("deleteById", com.my.MyClass object);
and I believe your class com.my.MyClass have something like
private String id;
and your xml would be
<delete id="deleteById" parameterType="com.my.MyClass">
DELETE FROM table
WHERE id = #{id}
</delete>
One possible way:
Assume MyClass.xml as below:
<mapper namespace = "com.my.MyClass">
<delete id="deleteById">
DELETE FROM table
WHERE id = #{id}
</delete>
</mapper>
Then
public class MyClass{
public int deleteById( #Param("id") int id );
}

org.postgresql.util.PSQLException: ERROR: syntax error at or near "user"

<dataset>
<user id="1" created_date='2017-01-01 00:00:00' email="" user_name="root"/>
</dataset>
xml above gives me error. The problem is i have reserved word for user. how can I solve this. any links?
updated
I am using spring boot, spring data jpa, spring-test-dbunit, dbunit, postgresql
According to this forum https://sourceforge.net/p/dbunit/mailman/message/20643023/ it doesn’t seem like DBUnit has a way to “quote” the table name. But you can configure DatabaseDataSourceConnectionFactoryBean if you do not want to rename tables for some reason or working with legacy database
#Configuration
public class Custom.... {
#Autowired
private DataSource dataSource;
#Bean
public DatabaseConfigBean dbUnitDatabaseConfig() {
DatabaseConfigBean dbConfigBean = new DatabaseConfigBean();
// dbConfigBean.setDatatypeFactory(new PostgresqlDataTypeFactory());
dbConfigBean.setQualifiedTableNames(true);
return dbConfigBean;
}
#Bean
public DatabaseDataSourceConnectionFactoryBean dbUnitDatabaseConnection() {
DatabaseDataSourceConnectionFactoryBean databaseDataSourceConnectionFactoryBean = new DatabaseDataSourceConnectionFactoryBean(dataSource);
databaseDataSourceConnectionFactoryBean.setDatabaseConfig(dbUnitDatabaseConfig());
return databaseDataSourceConnectionFactoryBean;
}
}
After setting true to qualifiedTableNames you should give full name for ur tables in xml
<public.user id="1" created_date='2017-01-01 00:00:00' email="root#demo.io" password="your password" username="root"/>

XMLSerialization issue

I need to generate the XML file which will be consumed by the external application. And I have observed that it depends on ordering of the namespace defined in the XML. Since the xml is consumed by external application, I don't have the exact error details.
Below is the sample code
[System.CodeDom.Compiler.GeneratedCodeAttribute("Xsd2Code", "3.4.0.32990")]
[System.SerializableAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Xml.Serialization.XmlTypeAttribute(Namespace="http://mycompany.com/2010/package")]
[System.Xml.Serialization.XmlRootAttribute("Catalog", Namespace="http://mycompany.com/2010/package", IsNullable=false)]
public partial class PackageT : System.ComponentModel.INotifyPropertyChanged {
}
Extension class written in order to include custom schemalocation
public partial class PackageT
{
[XmlAttributeAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string xsiSchemaLocation = "http://mycompany.com/2010/catalog.xsd";
}
Code to serialize the object to XML
XmlSerializerNamespaces namespaces = new XmlSerializerNamespaces();
namespaces.Add("xml", "http://www.w3.org/XML/1998/namespace");
namespaces.Add("test", "http://mycompany.com/2010/package");
XmlSerializer serializer = new XmlSerializer(typeof(PackageT));
TextWriter writer = new StreamWriter("package.xml");
serializer.Serialize(writer, catalog, namespaces);
writer.Flush();
writer.Close();
Generated XML ( not working)
<?xml version="1.0" encoding="utf-8"?>
<test:Catalog
xmlns:xml="http://www.w3.org/XML/1998/namespace"
d1p1:schemaLocation="http://mycompany.com/2010/catalog.xsd"
xmlns:d1p1="http://www.w3.org/2001/XMLSchema-instance" xmlns:test="http://mycompany.com/2010/package">
....
</test:Catalog>
EXpected XML which is working
<?xml version="1.0" encoding="utf-8"?>
<test:Catalog d1p1:schemaLocation="http://mycompany.com/2010/catalog.xsd"
xmlns:xml="http://www.w3.org/XML/1998/namespace"
xmlns:d1p1="http://www.w3.org/2001/XMLSchema-instance" xmlns:test="http://mycompany.com/2010/package">
....
</test:Catalog>
Please help me!!
If you specify the element name and namespace for the root you can generate the XML you're looking for. Modify PackageT as below:
[XmlRoot(ElementName = "Catalog", Namespace = "http://mycompany.com/2010/package") ]
public partial class PackageT
{
[XmlAttribute("schemaLocation", Namespace = "http://www.w3.org/2001/XMLSchema-instance")]
public string xsiSchemaLocation = "http://mycompany.com/2010/catalog.xsd";
}
and the output becomes:
<?xml version="1.0" encoding="utf-8"?>
<test:Catalog xmlns:xml="http://www.w3.org/XML/1998/namespace"
d1p1:schemaLocation="http://mycompany.com/2010/catalog.xsd"
xmlns:d1p1="http://www.w3.org/2001/XMLSchema-instance"
xmlns:test="http://mycompany.com/2010/package" />

MyBatis & RefCursor Parameter

Currently working on upgrading from iBatis to myBatis. In ibatis we would have a sql map like so
<resultMap id="PCRV_HIERARCHY_LVL_LIST_MAP" class="com.fmrco.sai.aadpm.domain.ConstraintHierarchyLevel">
<result property="levelId" column="LEVEL_ID"/>
<result property="levelDescription" column="LEVEL_DESCRIPTION"/>
<result property="levelRank" column="LEVEL_RANK"/>
<result property="levelCode" column="LEVEL_CODE"/>
</resultMap>
<parameterMap id="GET_HIERARCHY_LVL_LIST_MAP" class="java.util.Map">
<parameter property="PCRV_HIERARCHY_LVL_LIST" jdbcType="ORACLECURSOR" javaType="java.sql.ResultSet" mode="OUT" resultMap="PCRV_HIERARCHY_LVL_LIST_MAP"/>
</parameterMap>
<procedure id="GET_HIERARCHY_LVL_LIST" parameterMap="GET_HIERARCHY_LVL_LIST_MAP">
{ call GET_HIERARCHY_LVL_LIST ( ? ) }
</procedure>
I'd like to fully utilize the functionality provided by myBatis (such as not needing to implement an implementation of a mapper and avoiding using deprecated features such as parameterMap) but I'm having some issues. I kept running into errors trying to set the return properties so I had to wrap my resultSet object in a wrapper object which is something I'd like to avoid
Mapper.java
public void getHierarchyLevels(ListConstraintHierarchyLevel constraintHierarchyLevels);
ConstraintHierarchyLevel class
public class ListConstraintHierarchyLevel {
private List<ConstraintHierarchyLevel> constraintHierarchyLevels ;
public List<ConstraintHierarchyLevel> getConstraintHierarchyLevels() {
return constraintHierarchyLevels;
}
public void setConstraintHierarchyLevels(List<ConstraintHierarchyLevel> constraintHierarchyLevels) {
this.constraintHierarchyLevels = constraintHierarchyLevels;
}
}
mapper.xml
<resultMap id="HierarchyLvlMap" type="com.fmrco.sai.aadpm.domain.ConstraintHierarchyLevel">
<result property="levelId" column="LEVEL_ID"/>
<result property="levelDescription" column="LEVEL_DESCRIPTION"/>
<result property="levelRank" column="LEVEL_RANK"/>
<result property="levelCode" column="LEVEL_CODE"/>
</resultMap>
<select statementType="CALLABLE"
id="getHierarchyLevels"
parameterType="com.fmrco.sai.aadpm.domain.ListConstraintHierarchyLevel"
resultMap="HierarchyLvlMap">
{ call GET_HIERARCHY_LVL_LIST (
#{constraintHierarchyLevels,
jdbcType=CURSOR,
mode=OUT,
javaType=java.sql.ResultSet,
resultMap=HierarchyLvlMap}
) }
</select>
I have attempted another solution unsuccessfully. In this solution I make use of the param annotation
mapper.java
public void getHierarchyLevelsWithParam(#Param("constraintHierarchyLevels") List<ConstraintHierarchyLevel> constraintHierarchyLevels);
I use the same resultMap as above but with a different select block
mapper.xml
<select statementType="CALLABLE"
id="getHierarchyLevelsWithParam"
parameterType="list"
resultMap="HierarchyLvlMap">
{ call GET_HIERARCHY_LVL_LIST (
#{constraintHierarchyLevels,
jdbcType=CURSOR,
mode=OUT,
javaType=java.sql.ResultSet,
resultMap=HierarchyLvlMap}
) }
When running this I have debugged into the MapperMethod class to the execute method and the Object param gets the correct data from the result set however as this does not get placed into the argument sent down (List) these values do not get returned. When running the first method with the object wrapper the objects are placed in the argument sent down and thus are retrievable.
Thanks
I don't know any other way than wrapping result object.
Indeed, the OUT variable has to be bound on something, this is a variable scope issue, then indirection is mandatory. But it can be generic:
class Wrapper<T> {
private List<T> member;
}
The #Param annotation is actually used to give parameters a name to uses as reference in the SQL (especially if the mapper method has multiple parameters)