Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
181 views
in Technique[技术] by (71.8m points)

java - stream on JPA lazy list

I have JPA entity with list like this:

@OneToMany(mappedBy = "scadaElement", orphanRemoval = true)
private List<ElementParameter> elementParameters;

and map form ElementParameter

@ManyToOne
@JoinColumn(name = "SCADAELEMENT_ID")
ScadaElement scadaElement;

when i get entity with elementParameters list and do stream on it stream do nothing, even when I trigger list with .size() but when I do the same with a for loop it work.

System.out.println("elements size: " + s.getElementParameters().size());
s.getElementParameters()
            .stream()
            .forEach(
                    a -> { 
                        System.out.println("elementId: " + a.getId());
                    }
            );

Is there any solution to make that stream work? I use eclipselink as JPA provider.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Apparently, you are referring to this issue. These lazy lists using the anti-pattern of inheriting from actual implementations (here Vector) fail to adapt to the evolution of the base class. Note that there are two possible outcomes depending on how the anti-pattern was realized

  • If the lazily populated list populates itself (it terms of the inherited state) on the first use, the new inherited methods will start working as soon as a trigger property has been accessed for the first time
  • But if the list overrides all accessor methods to enforce delegation to another implementation, without ever updating the state of the base class, the base class’ methods which have not been overridden will never start working, even if the list has been populated (from the subclass’ point of view)

Apparently, the second case applies to you. Triggering the population of the list does not make the inherited forEach method work. Note that turning off the lazy population via configuration might be the simpler solution here.


To me, the cleanest solution would be if IndirectList inherits from AbstractList and adheres to the Collection API standard, now, almost twenty years after the Collection API has superseded Vector (should I mention how much younger JPA actually is?). Unfortunately, the developers didn’t go that road. Instead, the anti-pattern was maxed out by creating another class that inherits from the class which already inherits from the class not designed for inheritance. This class overrides the methods introduced in Java?8 and perhaps gets another subclass in one of the next Java releases.

So the good news is, developers expecting every List to be a Vector do not have to make up their minds, but the bad news is it doesn’t work as sometimes, you will not get the extended Java?8 specific version with JPA?2.6. But apparently, JPA?2.7 will work.

So you can derive a few alternative solutions:

  • Turn off lazy population
  • Stay with Java?7
  • Wait for JPA?2.7
  • just copy the collection, e.g.
    List<ElementParameter> workList=new ArrayList<>(elementParameters);
    This workList will support all Collection & Stream operations

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...