java.lang.ClassCastException:[B 无法转换为 [Ljava.lang.Object;在使用 JPA 2.2 query.getResultStream().findFirst() 时
java.lang.ClassCastException: [B cannot be cast to [Ljava.lang.Object; while using JPA 2.2 query.getResultStream().findFirst()
我的Spring数据存储方法的代码如下:
public Optional<byte[]> findShipmentLabelByClientIdAndAwb(String clientId, String awb) {
String queryString = "select g.shipmentLabel as shipmentLabel from GenericShipment g where g.client.id = :clientId and g.shipmentId = :awb " +
" AND (g.processingStatus is null or g.processingStatus <> 'DELETED') AND g.shipmentLabel is not null";
val query = entityManager.createQuery(queryString, byte[].class);
query.setParameter("clientId", clientId);
query.setParameter("awb", awb);
return query.getResultStream().findFirst();
}
如您所见,我正在尝试以字节数组的形式获取 shipmentLabel 列,该列在我的 Postgres 架构中定义为 bytea.
运行时出现以下异常:
java.lang.ClassCastException: [B cannot be cast to [Ljava.lang.Object;
at org.hibernate.internal.ScrollableResultsImpl.prepareCurrentRow(ScrollableResultsImpl.java:203)
at org.hibernate.internal.ScrollableResultsImpl.next(ScrollableResultsImpl.java:101)
at org.hibernate.query.internal.ScrollableResultsIterator.hasNext(ScrollableResultsIterator.java:33)
at java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1811)
at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126)
at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:499)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:486)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472)
at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:531)
at org.hibernate.query.spi.StreamDecorator.findFirst(StreamDecorator.java:260)
我想知道这是否是这里的预期行为,在此先感谢您的回答。
目前,解决方法是使用 JPA 2.1 变体:
return query.getResultList().stream().findFirst();
作为环境,我使用的是Spring Boot 2.3.3,Hibernate版本是5.4 .20.
字节没有原始流,您可以在调试器中检查您获得的流类型可能 Stream<Byte[]>
或 Stream<Object[]>
。这可以解释您遇到的异常。使用 Byte[] 应该可以解决您的问题。
public Optional<Byte[]> findShipmentLabelByClientIdAndAwb(String clientId, String awb) {
String queryString = "select g.shipmentLabel as shipmentLabel from GenericShipment g where g.client.id = :clientId and g.shipmentId = :awb " +
" AND (g.processingStatus is null or g.processingStatus <> 'DELETED') AND g.shipmentLabel is not null";
val query = entityManager.createQuery(queryString, Byte[].class);
query.setParameter("clientId", clientId);
query.setParameter("awb", awb);
return query.getResultStream().findFirst();
}
先用 getResultList
试一下,看看是否可行:
public Optional<Byte[]> findShipmentLabelByClientIdAndAwb(
String clientId, String awb) {
return entityManager.createQuery("""
select
g.shipmentLabel as shipmentLabel
from GenericShipment g
where
g.client.id = :clientId and
g.shipmentId = :awb and
(
g.processingStatus is null or
g.processingStatus <> 'DELETED'
) and
g.shipmentLabel is not null
""")
.setParameter("clientId", clientId)
.setParameter("awb", awb)
.setMaxResults(1)
.getResultList()
.stream()
.findFirst();
}
请注意,select N 条记录只取第一个使用 fidFirst
是低效的。如果这个查询 returns 100 条记录怎么办?您仍然 select 数据库中的全部 100。
这就是我添加 setMaxResults
调用的原因。
如果这不起作用,请尝试调试 Hibernate BinaryType
看看它为什么不起作用 return byte[]
.
我的Spring数据存储方法的代码如下:
public Optional<byte[]> findShipmentLabelByClientIdAndAwb(String clientId, String awb) {
String queryString = "select g.shipmentLabel as shipmentLabel from GenericShipment g where g.client.id = :clientId and g.shipmentId = :awb " +
" AND (g.processingStatus is null or g.processingStatus <> 'DELETED') AND g.shipmentLabel is not null";
val query = entityManager.createQuery(queryString, byte[].class);
query.setParameter("clientId", clientId);
query.setParameter("awb", awb);
return query.getResultStream().findFirst();
}
如您所见,我正在尝试以字节数组的形式获取 shipmentLabel 列,该列在我的 Postgres 架构中定义为 bytea. 运行时出现以下异常:
java.lang.ClassCastException: [B cannot be cast to [Ljava.lang.Object; at org.hibernate.internal.ScrollableResultsImpl.prepareCurrentRow(ScrollableResultsImpl.java:203) at org.hibernate.internal.ScrollableResultsImpl.next(ScrollableResultsImpl.java:101) at org.hibernate.query.internal.ScrollableResultsIterator.hasNext(ScrollableResultsIterator.java:33) at java.util.Spliterators$IteratorSpliterator.tryAdvance(Spliterators.java:1811) at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126) at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:499) at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:486) at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) at java.util.stream.FindOps$FindOp.evaluateSequential(FindOps.java:152) at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) at java.util.stream.ReferencePipeline.findFirst(ReferencePipeline.java:531) at org.hibernate.query.spi.StreamDecorator.findFirst(StreamDecorator.java:260)
我想知道这是否是这里的预期行为,在此先感谢您的回答。
目前,解决方法是使用 JPA 2.1 变体:
return query.getResultList().stream().findFirst();
作为环境,我使用的是Spring Boot 2.3.3,Hibernate版本是5.4 .20.
字节没有原始流,您可以在调试器中检查您获得的流类型可能 Stream<Byte[]>
或 Stream<Object[]>
。这可以解释您遇到的异常。使用 Byte[] 应该可以解决您的问题。
public Optional<Byte[]> findShipmentLabelByClientIdAndAwb(String clientId, String awb) {
String queryString = "select g.shipmentLabel as shipmentLabel from GenericShipment g where g.client.id = :clientId and g.shipmentId = :awb " +
" AND (g.processingStatus is null or g.processingStatus <> 'DELETED') AND g.shipmentLabel is not null";
val query = entityManager.createQuery(queryString, Byte[].class);
query.setParameter("clientId", clientId);
query.setParameter("awb", awb);
return query.getResultStream().findFirst();
}
先用 getResultList
试一下,看看是否可行:
public Optional<Byte[]> findShipmentLabelByClientIdAndAwb(
String clientId, String awb) {
return entityManager.createQuery("""
select
g.shipmentLabel as shipmentLabel
from GenericShipment g
where
g.client.id = :clientId and
g.shipmentId = :awb and
(
g.processingStatus is null or
g.processingStatus <> 'DELETED'
) and
g.shipmentLabel is not null
""")
.setParameter("clientId", clientId)
.setParameter("awb", awb)
.setMaxResults(1)
.getResultList()
.stream()
.findFirst();
}
请注意,select N 条记录只取第一个使用 fidFirst
是低效的。如果这个查询 returns 100 条记录怎么办?您仍然 select 数据库中的全部 100。
这就是我添加 setMaxResults
调用的原因。
如果这不起作用,请尝试调试 Hibernate BinaryType
看看它为什么不起作用 return byte[]
.