java.lang.ClassCastException: [B cannot be cast to [Ljava.lang.Object; while using JPA 2.2 query.getResultStream().findFirst()

huangapple go评论115阅读模式
英文:

java.lang.ClassCastException: [B cannot be cast to [Ljava.lang.Object; while using JPA 2.2 query.getResultStream().findFirst()

问题

以下是翻译好的内容:

我的Spring Data存储库方法的代码如下所示:

  1. public Optional<byte[]> findShipmentLabelByClientIdAndAwb(String clientId, String awb) {
  2. String queryString = "select g.shipmentLabel as shipmentLabel from GenericShipment g where g.client.id = :clientId and g.shipmentId = :awb " +
  3. " AND (g.processingStatus is null or g.processingStatus <> 'DELETED') AND g.shipmentLabel is not null";
  4. val query = entityManager.createQuery(queryString, byte[].class);
  5. query.setParameter("clientId", clientId);
  6. query.setParameter("awb", awb);
  7. return query.getResultStream().findFirst();
  8. }

正如您所见,我正在尝试获取名为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.3Hibernate版本为5.4.20

英文:

The code of my Spring Data repository method is as follows:

  1. public Optional&lt;byte[]&gt; findShipmentLabelByClientIdAndAwb(String clientId, String awb) {
  2. String queryString = &quot;select g.shipmentLabel as shipmentLabel from GenericShipment g where g.client.id = :clientId and g.shipmentId = :awb &quot; +
  3. &quot; AND (g.processingStatus is null or g.processingStatus &lt;&gt; &#39;DELETED&#39;) AND g.shipmentLabel is not null&quot;;
  4. val query = entityManager.createQuery(queryString, byte[].class);
  5. query.setParameter(&quot;clientId&quot;, clientId);
  6. query.setParameter(&quot;awb&quot;, awb);
  7. return query.getResultStream().findFirst();
  8. }

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,看看是否有效:

  1. public Optional<Byte[]> findShipmentLabelByClientIdAndAwb(
  2. String clientId, String awb) {
  3. return entityManager.createQuery("""
  4. select
  5. g.shipmentLabel as shipmentLabel
  6. from GenericShipment g
  7. where
  8. g.client.id = :clientId and
  9. g.shipmentId = :awb and
  10. (
  11. g.processingStatus is null or
  12. g.processingStatus <> 'DELETED'
  13. ) and
  14. g.shipmentLabel is not null
  15. """)
  16. .setParameter("clientId", clientId)
  17. .setParameter("awb", awb)
  18. .setMaxResults(1)
  19. .getResultList()
  20. .stream()
  21. .findFirst();
  22. }

注意,仅仅为了使用findFirst从中选择第一个记录而选择N条记录是低效的做法。如果此查询返回100条记录,那么仍将从数据库中选择全部100条记录。

这就是为什么我添加了setMaxResults调用。

如果这不起作用,请尝试调试Hibernate的BinaryType,看看为什么它不返回byte[]

英文:

Try with getResultList first, and see if it works:

  1. public Optional&lt;Byte[]&gt; findShipmentLabelByClientIdAndAwb(
  2. String clientId, String awb) {
  3. return entityManager.createQuery(&quot;&quot;&quot;
  4. select
  5. g.shipmentLabel as shipmentLabel
  6. from GenericShipment g
  7. where
  8. g.client.id = :clientId and
  9. g.shipmentId = :awb and
  10. (
  11. g.processingStatus is null or
  12. g.processingStatus &lt;&gt; &#39;DELETED&#39;
  13. ) and
  14. g.shipmentLabel is not null
  15. &quot;&quot;&quot;)
  16. .setParameter(&quot;clientId&quot;, clientId)
  17. .setParameter(&quot;awb&quot;, awb)
  18. .setMaxResults(1)
  19. .getResultList()
  20. .stream()
  21. .findFirst();
  22. }

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

  1. 没有字节的原始流您可以在调试器中检查获取的流的类型可能是`Stream<Byte[]>``Stream<Object[]>`这可以解释您遇到的异常使用Byte[]应该解决您的问题
  2. public Optional<Byte[]> findShipmentLabelByClientIdAndAwb(String clientId, String awb) {
  3. String queryString = "select g.shipmentLabel as shipmentLabel from GenericShipment g where g.client.id = :clientId and g.shipmentId = :awb " +
  4. " AND (g.processingStatus is null or g.processingStatus <> 'DELETED') AND g.shipmentLabel is not null";
  5. val query = entityManager.createQuery(queryString, Byte[].class);
  6. query.setParameter("clientId", clientId);
  7. query.setParameter("awb", awb);
  8. return query.getResultStream().findFirst();
  9. }
英文:

There is no primitive stream for byte, you can check in the debugger what type of stream your are getting maybe Stream&lt;Byte[]&gt; or Stream&lt;Object[]&gt;. This can explain the exception you are getting. Using Byte[] should solve your issue.

  1. public Optional&lt;Byte[]&gt; findShipmentLabelByClientIdAndAwb(String clientId, String awb) {
  2. String queryString = &quot;select g.shipmentLabel as shipmentLabel from GenericShipment g where g.client.id = :clientId and g.shipmentId = :awb &quot; +
  3. &quot; AND (g.processingStatus is null or g.processingStatus &lt;&gt; &#39;DELETED&#39;) AND g.shipmentLabel is not null&quot;;
  4. val query = entityManager.createQuery(queryString, Byte[].class);
  5. query.setParameter(&quot;clientId&quot;, clientId);
  6. query.setParameter(&quot;awb&quot;, awb);
  7. return query.getResultStream().findFirst();

}

huangapple
  • 本文由 发表于 2020年9月25日 15:19:51
  • 转载请务必保留本文链接:https://go.coder-hub.com/64059595.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定