javajpacollectionsjava-8java-stream

How to remove an element from a Set inside a Page of items based on a Condition using Java 8 streams


I have a Page of Farmers coming from a JPA repository call to a findAll method. Each Farmer consists of a Set of Farms which are also coming in the repository call like so:

public class Farmer {

private String name;
@ManyToMany
@JoinTable(name = "farmer_asset", joinColumns = @JoinColumn(name = "farmer_id", referencedColumnName = "id"), inverseJoinColumns = @JoinColumn(name = "asset_id", referencedColumnName = "id"))
private Set<Asset> assets;
}

Asset has a property called isActive which indicates that the asset is active or not.

In my Page of Farmers I want to select only farmers' Assets which are active.

I tried with @WhereJoinTable(clause = "is_active ='true'")

However, I learned that the is_active property is supposed to be in the intermediate many-to-many relation on table farmer_asset.

Now I am not in a position to change the entity structure, and use @WhereJoinTable(clause = "is_active ='true'").

So, I thought of trying to filter the values after making the JPA call.

However, iterating through each Farmer, then removing the inActive Assets and then adding it back to the Page and maintaining Page elements seemed too performance heavy operation.

I tried with normal Java code which looks something like this:

Page<Farmer> farmers = farmerRepository.findAll(pageable);

List<Farmer> farmersList = new LinkedList<>();

for (FarmerDto eachFarmer : farmers.getContent()) {

   Set<Asset> eachFarmerAssets = 
   eachFarmer.getAssets();

   eachFarmerAssets.removeIf(e -> 
   !e.getIsActive());

   eachFarmer.setAssets(eachFarmerAssets);              
   
   farmersList.add(eachFarmer);
}
return new PageImpl<FarmerDto>(farmersList, pageable, farmers.getTotalElements());

I would like to do this is Java 8 using streams but I am not able to iterate a list and change its element which is in turn a Set<Asset>.

Came here looking for some suggestions.


Solution

  • You actually don't to reassign the same reference to Set<Asset> because even the set has been modified, it's still the same object which is "known" to a particular farmer.

    And definitely you don't need streams for this task. Documentation suggests avoiding stateful operations and side-effects while designing stream pipe-lines.

    Instead, you can use forEach() method on a list:

    Page<Farmer> farmers = farmerRepository.findAll(pageable);
    List<Farmer> farmersList = new farmers.getContent();
        
    farmersList.forEach(farmer -> farmer.getAssets()
        .removeIf(e -> !e.getIsActive()));