Mybatis: IllegalArgumentException: Mapped Statements collection does not contain value for xxx - spring-boot

I have two entities Vendor and Goods with one-to-many relation, the relation looks like:
I am using mybatis with annotation, the mapper:
GoodsMapper
public interface GoodsMapper {
#Select("select * from goods where id=#{goodsId}")
#Results({
#Result(id = true, column = "id", property = "id"),
#Result(column = "name", property = "name"),
#Result(column = "vendor_id", property = "vendor",
one = #One(select = "com.xxx.server.mapper.VendorMapper.getVendor"))
})
Goods getGoods(#Param("goodsId") String goodsId);
}
VendorMapper
public interface VendorMapper {
#Select("select * from vendor where id=#{vendorId}")
Vendor getVendor(#Param("vendorId") String vendorId);
}
ignore the entity code & others...
when I invoked goodsMapper.getGoods(goodsId), I caught the following exception :
Caused by: org.apache.ibatis.exceptions.PersistenceException:
### Error querying database. Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.xxx.server.mapper.VendorMapper.getVendor
### The error may exist in com/xxx/server/mapper/GoodsMapper.java (best guess)
### The error may involve com.xxx.server.mapper.GoodsMapper.getGoods
### The error occurred while handling results
### SQL: select * from goods where id=?
### Cause: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.xxx.server.mapper.VendorMapper.getVendor
at org.apache.ibatis.exceptions.ExceptionFactory.wrapException(ExceptionFactory.java:30)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:150)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectList(DefaultSqlSession.java:141)
at org.apache.ibatis.session.defaults.DefaultSqlSession.selectOne(DefaultSqlSession.java:77)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:433)
... 117 more
Caused by: java.lang.IllegalArgumentException: Mapped Statements collection does not contain value for com.xxx.server.mapper.VendorMapper.getVendor
at org.apache.ibatis.session.Configuration$StrictMap.get(Configuration.java:933)
at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:726)
at org.apache.ibatis.session.Configuration.getMappedStatement(Configuration.java:719)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getNestedQueryMappingValue(DefaultResultSetHandler.java:740)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.getPropertyMappingValue(DefaultResultSetHandler.java:465)
at org.apache.ibatis.executor.resultset.DefaultResultSetHandler.applyPropertyMappings(DefaultResultSetHandler.java:441)
I have checked the class path com.xxx.server.mapper.VendorMapper.getVendor for the select of #One, it is correct.
Appreciate any kind help~

In my case this was caused by referenced collection not being initialized by Spring yet.
Solution is to add #DependsOn annotation to the "parent" mapper.
#DependsOn("VendorMapper")
public interface GoodsMapper{
...
}
#Repository("VendorMapper")
public interface VendorMapper {
...
}

Related

Conflicting enum values java

I have 2 enums defined as below in 2 separate files:
MyErrorCodes.java
#Getter
public enum MyErrorCodes implements ErrorCode {
ERROR1(90, 1, 01),
ERROR2(90, 1, 02),
ERROR3(90, 1, 03),
ERROR4(90, 1, 04),
ERROR5(90, 1, 05);
....
}
ErrorCategory.java
public class ErrorCategory {
#AllArgsConstructor
public enum ErrorCodes {
EXECUTION_ERROR("execution.error", "Error in executing {0}.", INTERNAL_ERROR,
MyErrorCodes.ERROR1),
DESERIALIZATION_ERROR("...", "...",BAD_REQUEST_ERROR, MyErrorCodes.ERROR2),
DEFAULT_INTERNAL_ERROR("...", "...", INTERNAL_ERROR, MyErrorCodes.ERROR3),
INVALID_RESPONSE("...", "...", INTERNAL_ERROR, MyErrorCodes.ERROR4),
MAPPING_ERROR("...", "...", INTERNAL_ERROR, MyErrorCodes.ERROR5);
}
}
At Runtime I am getting error:
Conflicting enum values. Name 'ERROR4' uses ordinal value (4) that is also used for name 'MAPPING_ERROR'
ERROR4 is 4th element in enum#1 while MAPPING_ERROR is 5th element in the enum#2.
Then Why am I getting conflict error when they are completely different enums?
P.S. the interface implemented by enum#1 looks like this:
public interface ErrorCode {
int getErrorCode();
String getKey();
}
stacktrace:
at io.opentracing.contrib.concurrent.TracedRunnable.run(TracedRunnable.java:30)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515)
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: org.apache.ignite.binary.BinaryObjectException: Conflicting enum values. Name 'ERROR4' uses ordinal value (4) that is also used for name 'MAPPING_ERROR'
at org.apache.ignite.internal.binary.BinaryUtils.mergeEnumValues(BinaryUtils.java:2538)
at org.apache.ignite.internal.binary.BinaryUtils.mergeMetadata(BinaryUtils.java:1028)
at org.apache.ignite.internal.processors.cache.binary.BinaryMetadataTransport.requestMetadataUpdate(BinaryMetadataTransport.java:211)
at org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl.addMeta(CacheObjectBinaryProcessorImpl.java:606)
at org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl$1.addMeta(CacheObjectBinaryProcessorImpl.java:288)
at org.apache.ignite.internal.binary.BinaryContext.registerUserClassDescriptor(BinaryContext.java:828)
at org.apache.ignite.internal.binary.BinaryContext.registerDescriptor(BinaryContext.java:784)
at org.apache.ignite.internal.binary.BinaryContext.registerClass(BinaryContext.java:581)
at org.apache.ignite.internal.binary.BinaryContext.registerClass(BinaryContext.java:556)
at org.apache.ignite.internal.binary.BinaryWriterExImpl.doWriteEnum(BinaryWriterExImpl.java:829)
at org.apache.ignite.internal.binary.BinaryWriterExImpl.writeEnumField(BinaryWriterExImpl.java:1323)
at org.apache.ignite.internal.binary.BinaryFieldAccessor$DefaultFinalClassAccessor.write0(BinaryFieldAccessor.java:670)
at org.apache.ignite.internal.binary.BinaryFieldAccessor.write(BinaryFieldAccessor.java:157)
... 115 common frames omitted
```
Okay so here is what we did and found out regarding the issue:
We were using ignite cluster for our deployment purpose, we updated the ignite version from 6 to 7 and that solved the issue.
Ignite caches the enum values, so When we introduce new enum values we should add to the end to increment the ordinal to avoid conflicts in future or clear the cache.

ERROR - new Global exception handled! Message = java.util.LinkedHashMap cannot be cast to java.math.BigInteger

DataType of patientId is BigInteger in entity Object
private BigInteger patientId;
Code:
#Override
public List<ChatRoomHistory> getLastChatDetails(List<String> patientIds) {
String queryStr = "FROM ChatRoomHistory where type = 'NO' and patientId in :patientIds ORDER BY chatCloseTime DESC";
TypedQuery<ChatRoomHistory> query = sessionFactory.getObject().getCurrentSession().createQuery(queryStr, ChatRoomHistory.class);
query.setParameter("patientIds", patientIds);
return query.getResultList();
}
Error
2020-08-16 19:52:27,939 [http-nio-8080-exec-5:] c.t.c.u.e.GlobalExceptionHandler.handleException:243
ERROR - new Global exception handled! Message = java.util.LinkedHashMap cannot be cast to java.math.BigInteger
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to java.math.BigInteger
at org.hibernate.type.descriptor.java.BigIntegerTypeDescriptor.unwrap(BigIntegerTypeDescriptor.java:19)
at org.hibernate.type.descriptor.sql.DecimalTypeDescriptor$1.doBind(DecimalTypeDescriptor.java:47)
at org.hibernate.type.descriptor.sql.BasicBinder.bind(BasicBinder.java:74)
at org.hibernate.type.AbstractStandardBasicType.nullSafeSet(AbstractStandardBasicType.java:280)
Like said in the comment, you can't pass a list of String as a parameter intended for a numeric field.
You should declare your parameter as
public List<ChatRoomHistory> getLastChatDetails(List<BigInteger> patientIds)
You can correct your method in this way:
#Override
public List<ChatRoomHistory> getLastChatDetails(List<BigInteger> patientIds)
{
String hql = "select c from ChatRoomHistory c where c.type = 'NO' and c.patientId in :patientIds ORDER BY c.chatCloseTime DESC";
TypedQuery<ChatRoomHistory> query = sessionFactory.getCurrentSession().createQuery(hql, ChatRoomHistory.class);
query.setParameter("patientIds", patientIds);
return query.getResultList();
}
Comments:
Even though HQL does not require the presence of a select_clause, it is generally good practice to include one.
The list of values must not be empty; it must contain at least one value. (See this).

calcite select count(intCol) from table when row type is _MAP (elasticsearch example)

I'm new to Calcite. The functionality it provides look fabulous!
While doing a research, I'm trying to figure out how to do some basic SQL queries with example ElasticSearch adapter.
In the AbstractElasticsearchTable.getRowType, it maps rows to a MAP.
The issue is:
Query:
select * from zips where \"city\" = 'BROOKLYN'
returns:
city=BROOKLYN; longitude=-73.956985; latitude=40.646694; pop=111396; state=NY; id=11226
Query:
select \"pop\" from zips where \"city\" = 'BROOKLYN'
returns:
pop={pop=111396}
My goal is to sum up all the 'pop' values.
So when I construct query like this:
select sum(\"pop\") from zips where \"city\" = 'BROOKLYN'
The error is:
Caused by: java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to java.lang.Integer
at Baz$2.apply(Unknown Source)
at Baz$2.apply(Unknown Source)
at org.apache.calcite.linq4j.EnumerableDefaults.aggregate(EnumerableDefaults.java:117)
at org.apache.calcite.linq4j.DefaultEnumerable.aggregate(DefaultEnumerable.java:107)
at Baz.bind(Unknown Source)
at org.apache.calcite.jdbc.CalcitePrepare$CalciteSignature.enumerable(CalcitePrepare.java:356)
Can somebody point me to the right direction to figure out how to do aggregations with such mapping like in example?
To execute this query I added a test into ElasticSearchAdapterTest.java.
#Test
public void select() {
CalciteAssert.that().with(newConnectionFactory())
.query("select sum(\"pop\") from zips where \"city\" = 'BROOKLYN'").returns("");
}
Implementation of RowType as StructType resolved my issue. Here it is:
public RelDataType getRowType(RelDataTypeFactory typeFactory) {
try {
Map<String, String> mapping = getMapping();
List<RelDataType> types = new ArrayList<RelDataType>();
List<String> names = new ArrayList<>();
for(Map.Entry<String, String> e : mapping.entrySet()) {
names.add(e.getKey());
types.add(translateEsType(e.getValue(), typeFactory));
}
return typeFactory.createStructType(types, names);
} catch(IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}

Unable to locate table meta data for table

I am using Spring and my class is annotated with #Transactional.
I am using the SimpleJdbcInsert but I am getting the following warning:
TableMetaDataProvider: - Unable to locate table meta data for
'data.data_insert' -- column names must be provided
I have three tables and all the three are having the relationship such that:
primary key of table1 is the foreign key in table 2 and the primary key in table 2 is the foreign key in table 3.
Showing table 1 insert code:
java.sql.Timestamp timestamp = getCurrentJavaSqlTimestamp();
Map<String, Object> params = new HashMap<String, Object>();
params.put("notes", task.getNotes());
params.put("recording_time", timestamp);
params.put("end_user_id", 805);
SimpleJdbcInsert insertData = new SimpleJdbcInsert(dataSource).
withTableName("data.data_insert").
usingColumns("notes", "recording_time",
"end_user_id").usingGeneratedKeyColumns("data_id");
long dataId = insertData.executeAndReturnKey(params).longValue();
The error logs:
2015-09-29 14:10:27,133 WARN [http-8080-2] LegacyFlexJsonExceptionMessageConverter: - Generated Key Name(s) not specificed. Using the generated keys features requires specifying the name(s) of the generated column(s) for User ID: 805, Request ID: f8da3bb5-0613-4a74-9ca8-95a6ab4f1692, clientIP: 127.0.0.1 uri: /admin/dataInsert, Request Parameters:
org.springframework.dao.InvalidDataAccessApiUsageException: Generated Key Name(s) not specificed. Using the generated keys features requires specifying the name(s) of the generated column(s)
at org.springframework.jdbc.core.simple.AbstractJdbcInsert.prepareStatementForGeneratedKeys(AbstractJdbcInsert.java:530)
at org.springframework.jdbc.core.simple.AbstractJdbcInsert.access$0(AbstractJdbcInsert.java:528)
at org.springframework.jdbc.core.simple.AbstractJdbcInsert$1.createPreparedStatement(AbstractJdbcInsert.java:448)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:581)
at org.springframework.jdbc.core.JdbcTemplate.update(JdbcTemplate.java:843)
at org.springframework.jdbc.core.simple.AbstractJdbcInsert.executeInsertAndReturnKeyHolderInternal(AbstractJdbcInsert.java:445)
at org.springframework.jdbc.core.simple.AbstractJdbcInsert.executeInsertAndReturnKeyInternal(AbstractJdbcInsert.java:426)
at org.springframework.jdbc.core.simple.AbstractJdbcInsert.doExecuteAndReturnKey(AbstractJdbcInsert.java:380)
at org.springframework.jdbc.core.simple.SimpleJdbcInsert.executeAndReturnKey(SimpleJdbcInsert.java:122)
at com.gridpoint.energy.datamodel.impl.PGDataFixBackUpManagerBean.backupDataInRange(PGDataFixBackUpManagerBean.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:319)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
The correct one:
java.sql.Timestamp timestamp = getCurrentJavaSqlTimestamp();
Map<String, Object> params = new HashMap<String, Object>();
params.put("notes", task.getNotes());
params.put("recording_time", timestamp);
params.put("end_user_id", 805);
SimpleJdbcInsert insertData = new
SimpleJdbcInsert(dataSource).withSchemaName("data").
withTableName("data_insert")
usingColumns("notes", "recording_time",
"end_user_id").usingGeneratedKeyColumns("data_id");
long dataId = insertData.executeAndReturnKey(params).longValue();
So just needed a schemaName using withSchemaName.

How do I query Hibernate for object where property may be null or specific value?

I have the following objects I'm working with:
RawRead
RawRead.Checkpoint
Checkpoint.EndCustomer
Guard
Where Checkpoint and Guard are properties of RawRead, EndCustomer is a property of Checkpoint. All are objects.
My current Hibernate gubbins:
Criteria crit = sess.createCriteria(RawRead.class);
crit.add(
Restrictions.or(
Restrictions.eq("checkpoint", null),
Restrictions.in("checkpoint.parentEndCustomer",collectionOfEndCustomers)
)
);
So Checkpoint can be null, but if it is there I only want the RawRead objects where the parentEndCustomer object is in the checkpoint.parentEndCustomer property.
I hope that makes sense.
My guesstimate above produces an error that (to me) suggests that my criteria are incorrectly specified:
[Request processing failed; nested exception is org.hibernate.QueryException: could not resolve property: checkpoint.parentEndCustomer of: uk.co.romar.guardian.objects.RawRead] with root cause org.hibernate.QueryException:
could not resolve property: checkpoint.parentEndCustomer of: uk.co.romar.guardian.objects.RawRead at
org.hibernate.persister.entity.AbstractPropertyMapping.propertyException(AbstractPropertyMapping.java:81) at
org.hibernate.persister.entity.AbstractPropertyMapping.toColumns(AbstractPropertyMapping.java:96) at
org.hibernate.persister.entity.BasicEntityPropertyMapping.toColumns(BasicEntityPropertyMapping.java:62) at
org.hibernate.persister.entity.AbstractEntityPersister.toColumns(AbstractEntityPersister.java:1457) at
org.hibernate.loader.criteria.CriteriaQueryTranslator.getColumns(CriteriaQueryTranslator.java:483)
Relevant bits of RawRead:
#ManyToOne
#JoinColumn(name="CHECKPOINT_OID")
#NotFound(action=NotFoundAction.IGNORE)
public Checkpoint checkpoint = null;
public void setCheckpoint(Checkpoint in) {this.checkpoint = in;}
public Checkpoint getCheckpoint() {return this.checkpoint;}
#ManyToOne
#JoinColumn(name="GUARD_OID")
#NotFound(action=NotFoundAction.IGNORE)
private Guard guard = null;
public void setGuard(Guard in) {this.guard = in;}
public Guard getGuard() {return this.guard;}
And from Checkpoint:
#ManyToOne
#JoinColumn(name="ENDCUSTOMER_OID")
#NotFound(action=NotFoundAction.IGNORE)
private EndCustomer parentEndCustomer = null;
public EndCustomer getParentEndCustomer() {return this.parentEndCustomer;}
public void setParentEndCustomer(EndCustomer ownerCustomer) {this.parentEndCustomer = ownerCustomer;}
EDIT Follows after implementing first answer from below.
If I have some data like this in the database (I hope the notation makes sense!):
RawRead {
ID=1
checkpoint={id=1,parentEndCustomer={ID=1}}
}
RawRead {
ID=2
checkpoint={id=4,parentEndCustomer={ID=4}}
}
RawRead {
ID=3
checkpoint={id=7,parentEndCustomer={ID=31}}
}
RawRead {
ID=4
checkpoint={null}
}
and the collectionOfEndCustomers given in the Restriction is like this:
EndCustomer={ID=31}
The I would want to retrieve RawReads 3 and 4 only. RawRead 1 & 2 are rejected because the parentEndCustomer of the child checkpoint property does't match the one passed in to the restriction in collectionOfEndCustomers.
RawRead.3 is should be selected because the parentEndCustomer matches one in the collection passed in. RawRead.4 should be selected because the checkpoint is null.
Following the guidance in the first answer below results in all of the above RawReads being returned rather than the subset I'm after.
You can't chain properties like you would do in HQL. You must use joins, with Criteria. And since checkpoint can be null, you must use a left join. Moreover, Restrictions.eq() can't be used to compare something with null (as in HQL and SQL). You must use Restrictions.isNull() to do that.
So your query should look like this:
Criteria crit = sess.createCriteria(RawRead.class, "rawRead");
crit.createAlias("rawRead.checkpoint", "checkpoint", Criteria.LEFT_JOIN)
crit.add(
Restrictions.or(
Restrictions.isNull("checkpoint.id"),
Restrictions.in("checkpoint.parentEndCustomer", collectionOfEndCustomers)
)
);

Resources