AssertJ Verify List of Objects with a List field is not empty - assertj

Example:
public class Office {
List<Employee> employee;
}
How do I assert that in my List<Office> offices there are none with no employees? Is it possible to assert this with one assertion chain?

If I understand your question correctly you want to check that all offices have employee, if so allSatisfy can be used like:
assertThat(offices).allSatisfy(office -> {
assertThat(office.employee).isNotEmpty();
});
There is also a noneSatisfy assertion available BTW.

You could solve this via allSatisfy iterable assertion like shown in the following example:
#Test
public void assertInnerPropertyInList() {
List<Office> officesWithEmptyOne = List.of(
new Office(List.of(new Employee(), new Employee())),
new Office(List.of(new Employee())),
new Office(List.of()));
List<Office> offices = List.of(
new Office(List.of(new Employee(), new Employee())),
new Office(List.of(new Employee())));
// passes
assertThat(offices).allSatisfy(office -> assertThat(office.getEmployee()).isNotEmpty());
// fails
assertThat(officesWithEmptyOne).allSatisfy(office -> assertThat(office.getEmployee()).isNotEmpty());
}
#Data
#NoArgsConstructor
#AllArgsConstructor
public class Office {
private List<Employee> employee;
}
#Data
#AllArgsConstructor
public class Employee {
}
And you can see that the second assertion fails with the message:
java.lang.AssertionError:
Expecting all elements of:
<[AssertJFeatureTest.Office(employee=[AssertJFeatureTest.Employee(), AssertJFeatureTest.Employee()]),
AssertJFeatureTest.Office(employee=[AssertJFeatureTest.Employee()]),
AssertJFeatureTest.Office(employee=[])]>
to satisfy given requirements, but these elements did not:
<AssertJFeatureTest.Office(employee=[])>
Expecting actual not to be empty
Annotations are coming from Lombok.

Related

How can I use JPA Query Methods to return an OR condition with NULL?

Am trying to create a Query that either matches all rows that equal tier or are NULL. Using Query Methods as described in Spring JPA Docs. The Default implementation below works if I just pass in the tier:-
#Entity
#Table(name = "tier")
class UuTier {
Long id;
Long tierId;
}
#Entity
#Table(name = "user")
class User {
#OneToOne
#JoinColumn(name="tier_id")
UuTier uuTier;
// Other Relationships
}
public interface UserRepository extends Repository<User, Long> {
List<User> findByTier_Id(#Param("tier")Long tier);
}
What I need is something like this, which is throwing an error " No property null found for type User". Can I achieve this ask using Query Methods?:-
public interface UserRepository extends Repository<User, Long> {
List<User> findByTierOrNull_Id(#Param("tier")String tier);
}
Following up from one of the responders (who for some reason deleted her post) - I got this to work!!
#Query("SELECT entity FROM User entity LEFT JOIN UuTier uuTier ON entity.uuTier.tier = uuTier.tier"
+ " WHERE entity.uuTier.tier = :tier OR entity.uuTier.tier IS NULL")
public List<User> findByTierOrNull_Id(#Param("tier") Long tier);

Entity with CascadeType.ALL in OneToMany not persisting children

I'm working with a 3rd party library provided to our team where one of the entities has a OneToMany relationship to entities of the same type of itself. I've changed the entity name to keep it anonymous.
Probably there's a better way of annotating entities with this type of relationship but as it's provided by a 3rd party I'm avoiding making to many changes so that it's compatible with future patches and updates.
It's using OpenJPA 2.4.0-ep2.0
#Entity
#Table(name = Person.TABLE_NAME)
public class Person {
private Long parentUid;
private List<Person> children = new ArrayList<>();
#OneToMany(targetEntity = Person.class, cascade = { CascadeType.ALL }, fetch = FetchType.LAZY)
#ElementJoinColumn(name = "PARENT_UID")
#ElementForeignKey
#ElementDependent
public List<Person> getChildren() {
return this.children;
}
}
When I try to persist a person with children, only the main entity gets persisted and children ignored.
However, if I change the fetch attribute to FetchType.EAGER it works (it persists both the parent and children). My understanding was that the fetch type only affects the loading, not the inserting. Any ideas why is it happening?
Also, is there a way of making it work while keeping the fetch type to FetchType.LAZY?
I've tried the following (modify the setter):
protected void setChildren(final List<Person> children) {
if (Objects.nonNull(children)) {
for (Person child : children) {
child.setParentUid(parentUid);
}
this.childItems = children;
} else {
this.childItems = new ArrayList<>();
}
}
Problem is in the child entity ,you should use #ManyToOne annotation in child entity.
add following code to Person :
public class person {
.
.
#MantToOne(fetch=FetchType.LAZY)
#JoinClolumn(name="PARENT_UID")
private Person parent;
public void setParent(Person parent){
}
.
.
}
then revise setChildren Code like this:
protected void setChildren(final List<Person> children) {
if (Objects.nonNull(children)) {
for (Person child : children) {
child.setParent(this);
}
this.childItems = children;
} else {
this.childItems = new ArrayList<>();
}
}
one important point is ،always fetch type must be sync in parent and child.

how to filter out entity object inside entity in rest api

I am using Spring Boot to implement rest api. There are three entities SeqTb, PairTb, and GroupTb and they are nested. SeqTb has manytoone with PairTb. PairTb has onetomany relationship with SeqTb and also manytoone with GroupTb.
//SeqTb.java
#Entity
#Table(name="SEQ_TB")
public class SeqTb implements Serializable {
.......
#ManyToOne
#JoinColumn(name="PAIR_ID")
private PairTb pairTb;
......
}
// PairTb.java
#Entity
#Table(name="PAIR_TB")
#NamedQuery(name="PairTb.findAll", query="SELECT p FROM PairTb p")
public class PairTb implements Serializable {
#ManyToOne
#JoinColumn(name="GROUP_ID")
private GroupTb groupTb;
#OneToMany(mappedBy="pairTb", cascade=CascadeType.ALL)
private List<SeqTb> seqTbs;
}
//GroupId.java
#Entity
#Table(name="GROUP_TB")
public class GroupTb implements Serializable {
//bi-directional many-to-one association to PairTb
#OneToMany(mappedBy="groupTb", cascade=CascadeType.ALL)
private List<PairTb> pairTbs;
}
In my controller GET request with analysisId was handled in the following way:
#RequestMapping(
value = "/api/seqs/{analysis_id}",
method = RequestMethod.GET,
produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<SeqTb> getSeqByAnalysisId(#PathVariable("analysis_id") String analysis_id) {
SeqTb seq = seqService.findByAnalysisId(analysis_id);
return new ResponseEntity(seq, HttpStatus.OK);
}
I also create a bean class SeqServiceBean that extends the interface SeqService which in turn calls methods from the following JPA repository for query.
//SeqRepository.java
#Repository
public interface SeqRepository extends JpaRepository<SeqTb, Integer> {
#Override
public List<SeqTb> findAll();
public List<SeqTb> findByAnalysisId(String analysisId);
}
When I query a SeqTb object with SeqTb.PairTb == null, the api works just fine. However, if the analysisId I put in the url belongs to a SeqTb record that associates with a pairId which in turn belongs to a groupId, the program would go nuts. Below is the output, the first part output is correct (bold text). After that it keeps printing PairTb and GroupTb in loops (repeating keywords pairTb, groupTb).
{"rowId":8,"analysisId":"cce8d2c2-a6dc-4ee9-ba97-768f058abb50","analyteCode":"D","center":"UCSC",
"pairTb":{"rowId":4,"pairCode":"01ad975d-c2ed-4e4d-bd3b-c9512fc9073c","groupTb":{"rowId":1,"groupName":"PAWG_pilot-50","pairTbs":[{"rowId":1,"pairCode":"00ad0ffe-2105-4829-a495-1c2aceb5bb31","groupTb":{"rowId":1,"groupName":"PAWG_pilot-50","pairTbs":
Meanwhile I got lots of errors from tomcat server:
Caused by: java.lang.IllegalStateException: getOutputStream() has already been called for this response
at org.apache.catalina.connector.Response.getWriter(Response.java:565) ~[tomcat-embed-core-8.0.32.jar:8.0.32]
at org.apache.catalina.connector.ResponseFacade.getWriter(ResponseFacade.java:212) ~[tomcat-embed-core-8.0.32.jar:8.0.32]
How do I ignore the nested entity object inside an entity and get only the meaning columns?
You can also annotate a property with #JsonIgnore in order to not output that field.
Found the solution. Created a value object that only contains the specific columns from entity and leave out the nested entity object. And it works.

Handling dependent entities when deleting the principal with Entity Framework 5

Here's the situation in its most simplified form using the EF5 Code-First approach:
public abstract class EntityBase<PK>
{
public PK ID { get; set; }
}
public class Country : EntityBase<string>
{
public string Name { get; set; }
}
public class Address : EntityBase<int>
{
[Required]
public string CountryID { get; set; }
public Country Country { get; set; }
// ... other address properties ...
}
The one-to-many relationship between Address and Country is set up with no cascade-delete like so:
modelBuilder.Entity<Address>()
.HasRequired(a => a.Country)
.WithMany()
.HasForeignKey(a => a.CountryID)
.WillCascadeOnDelete(false);
Finally, I have a generic base repository class with CRUD methods that call SaveChanges on the underlying DbContext to commit data changes atomically. E.g.:
public class EFRepository<T, PK> : IRepository<T, PK> where T : EntityBase<PK>
{
//
// ... other methods ...
//
public virtual void Delete(T instance)
{
// ... trigger validations, write to log, etc...
_dbContext.Set<T>().Remove(instance);
try
{
_dbContext.SaveChanges();
}
catch(Exception ex)
{
// ... handle the error ...
}
}
}
Part 1:
Scenario:
var countryRepo = new EFRepository<Country>();
var country = countryRepo.Save(new Country() { ID="??", Name="Test Country" });
var addressRepo = new EFRepository<Address>();
var address = addressRepo.Save(new Address() { Country=country });
countryRepo.Delete(country);
This should fail due to the existence of a dependent Address. However, afterwards the address ends up with a null in CountryID, which is invalid because Address.CountryID is required, so subsequent SaveChanges calls throw a validation exception unless the address is detached.
I expected that when an object is deleted, EF5 will be smart enough to first check for any cascade-delete constraints like the one above and, failing to find any, then proceed to delete the data. But exactly the opposite seems to be the case.
Is this a normal behaviour or am I doing something wrong?
Part 2:
Following a failed SaveChanges call, some Addresses are now in an invalid state in my DbContext and need to be restored to their original values. Of course, I can always do so explicitly for each entity type (Country, State, Order, etc.) by creating specialized repository classes and overriding Delete, but it smells big time. I'd much rather write some general purpose code to gracefully recover related entities after a failed SaveChanges call.
It would require interrogating DbContext to get all relationships in which an entity (e.g. Country) is the principal, regardless of whether or not its class defines navigational properties to dependent entities.
E.g. Country has no Addresses property, so I need to somehow find in DbContext the definition of the one-to-many relationship between Country and Address and use it to restore all related Addresses to their original values.
Is this possible?
Answering my own question in Part 2:
Here is my approach to checking for related dependents when deleting an entity on the principal end of a many-to-one relationship and where dependents are NOT exposed as a navigation collection in the principal (e.g. class Address has a Country property, but class Country doesn't have an Addresses collection).
DbContext
Add the following method to the context class:
/// <summary>
/// Returns an array of entities tracked by the
/// context that satisfy the filter criteria.
/// </summary>
public DbEntityEntry[] GetTrackedEntities<T>(
Expression<Func<DbEntityEntry<T>, bool>> filterCriteria)
where T : class
{
var result = new List<DbEntityEntry>();
var doesItMatch = filterCriteria.Compile();
foreach (var entry in this.ChangeTracker.Entries<T>())
{
if (doesItMatch(entry))
result.Add(entry);
}
return result.ToArray();
}
Repositories
Create a repository for each class that has some dependencies, override the Delete method and use the new GetTrackedEntities<T> method to get all related dependents and either:
explicitly delete them if they are cascade-deletable in code
detach them from the context if they are cascade-deletable in the DB itself
throw an exception if they are NOT cascade-deletable.
Example of the latter case:
public class EFCountryRepository :
EFReadWriteRepository<Country, string>,
ICountryRepository
{
public override void Delete(Country instance)
{
// Allow the Country to be deleted only if there are no dependent entities
// currently in the context that are NOT cascade-deletable.
if (
// are there any Regions in the context that belong to this Country?
_dbContext.GetTrackedEntities<Region>(e =>
e.Entity.CountryID == instance.ID ||
e.Entity.Country == instance).Length > 0
||
// are there any Addresses in the context that belong to this Country?
_dbContext.GetTrackedEntities<Address>(e =>
e.Entity.CountryID == instance.ID ||
e.Entity.Country == instance).Length > 0
)
throw new Exception(String.Format(
"Country '{0}' is in use and cannot be deleted.", instance.ID));
base.Delete(instance);
}
// ... other methods ...
}
Example of a case where cascade-deleting will be done by the DB itself, so all we need to do is detach the dependents from the context:
public class EFOrderRepository :
EFReadWriteRepository<Order, string>,
IOrderRepository
{
public override void Delete(Order instance)
{
foreach (var orderItem in _dbContext.GetTrackedEntities<OrderItem>(e =>
e.Entity.OrderID == instance.ID ||
e.Entity.Order == instance))
{
_dbContext.Entry(orderItem).State = System.Data.EntityState.Detached;
}
base.Delete(instance);
}
// ... other methods ...
}
Hope someone will find this solution helpful.

OpenJPA - lazy fetching does not work

I have a specific problem with an unit test using embedded OpenEJB container. I have a bi-directional relation between two classes. In one direction the relation works properly, but in the opposite direction the relation works only in EAGER-mode. In LAZY-mode the field section stays null. The code snipped follows:
#Entity
#Table(name="tracks")
class TrackEntity implements Track {
#Id
private int trackNumber;
#OneToMany(mappedBy = "track")
private HashSet<SectionEntity> sections;
public TrackEntity() {
sections = new HashSet<SectionEntity>();
}
#Override
public Collection<HistoricalEvent> getEvents() {
if (sections == null)
throw new CommonError("number=" + trackNumber, AppErrors.TRACK_EMPTY);
TreeSet<HistoricalEvent> set = new TreeSet<HistoricalEvent>();
for (SectionEntity se : sections)
set.addAll(se.getEvents());
return set;
}
}
My code is little bit specific. The class uses the field sections just internally to merge all sub-collections. I'm unable to fill sections lazily. I thing, the container expects client to access the field externally via a getter.
Its the problem with life cycle of enties. All enties (track and its sections) must be re-attached to the persistence context. The method collecting events must be in the class using EntityManager. (The entity cannot use the manager to re-attach itself.) Example of updated entity managing class follows:
public class EntityDataAccessor {
#PersistenceUnit(unitName = "someUnit")
private EntityManagerFactory emFactory;
//gets one track
public Track getTrack(int number) {
EntityManager em = emFactory.createEntityManager();
try {
return (Track)em.find(TrackEntity.class, number);
}
finally {
em.close();
}
}
//the new method collecting events
public Collection<HistoricalEvent> getEventsForTrack(TrackEntity te) {
EntityManager em = emFactory.createEntityManager();
te = em.merge(te); //re-attach to the context
Set<SectionEntity> sections = te.getSections();
TreeSet<HistoricalEvent> set = new TreeSet<HistoricalEvent>();
for (SectionEntity se : sections) {
se = em.merge(se); //re-attach to the context
set.addAll(se.getEvents());
}
em.close();
return set;
}
}
See question What's the lazy strategy and how does it work? for more detail.