英文:
java.lang.ClassCastException: [B cannot be cast to [Ljava.lang.Object; while using JPA 2.2 query.getResultStream().findFirst()
问题
以下是翻译好的内容:
我的Spring Data存储库方法的代码如下所示:
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强制转换为[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。
英文:
The code of my Spring Data repository method is as follows:
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();
}
As you can see, I am attempting to fetch, as byte array, the shipmentLabel column, defined in my Postgres schema as bytea.
The following exception occurs at runtime:
> 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)
I was wondering if this is the intended behaviour here or not, thanks in advance for your answers.
For the time being, the workaround is to use the JPA 2.1 variant:
> return query.getResultList().stream().findFirst();
As environment, I am using Spring Boot 2.3.3, Hibernate version is 5.4.20.
答案1
得分: 3
尝试首先使用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();
}
注意,仅仅为了使用findFirst
从中选择第一个记录而选择N条记录是低效的做法。如果此查询返回100条记录,那么仍将从数据库中选择全部100条记录。
这就是为什么我添加了setMaxResults
调用。
如果这不起作用,请尝试调试Hibernate的BinaryType
,看看为什么它不返回byte[]
。
英文:
Try with getResultList
first, and see if it works:
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();
}
Note that it's inefficient to select N records only to take the first one using fidFirst
. What if this query returns 100 records? You'd still select all 100 from the DB.
That's why I added the setMaxResults
call.
If that doesn't work, try debugging the Hibernate BinaryType
and see why it doesn't return byte[]
.
答案2
得分: 0
没有字节的原始流,您可以在调试器中检查获取的流的类型,可能是`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();
}
英文:
There is no primitive stream for byte, you can check in the debugger what type of stream your are getting maybe Stream<Byte[]>
or Stream<Object[]>
. This can explain the exception you are getting. Using Byte[] should solve your issue.
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();
}
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论