Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -668,6 +668,33 @@ public void setTenantValue(EntityBean entityBean, Object tenantId) {
setValue(entityBean, tenantId);
}

/**
* By default, getIntercept and setIntercept will check, if the passed bean is an instance of descriptor type.
* <p>
* If the property is not part of the type hierarchy (i.e. is this property from this descriptor)
* an UnsuppoertedOperation is thrown.
* <p>
* If inheritance is involved, this method returns false instead of an exception, if the property might exist in
* one of the child beans. This is necessary for getIntercept, as it returns <code>null</code> in this case.
* @return true if property can be
*/
private boolean checkPropertyAccess(EntityBean bean) {
if (bean == null || descriptor.type().isInstance(bean)) { // null = fall through - NPE is catched later.
return true;
}
InheritInfo inheritInfo = descriptor.inheritInfo();
if (inheritInfo == null || inheritInfo.isRoot() || !inheritInfo.getRoot().getType().isInstance(bean)) {
throw new IllegalArgumentException(propertyIncomatibleMsg(bean));
} else {
return false;
}
}

private String propertyIncomatibleMsg(EntityBean bean) {
String beanType = bean == null ? "null" : bean.getClass().getName();
return "Property " + name + " on [" + descriptor + "] is incompatible with type[" + beanType + "]";
}

/**
* Set the value of the property without interception or
* PropertyChangeSupport.
Expand All @@ -684,6 +711,9 @@ public void setValue(EntityBean bean, Object value) {
* Set the value of the property.
*/
public void setValueIntercept(EntityBean bean, Object value) {
if (!checkPropertyAccess(bean)) {
throw new IllegalArgumentException(propertyIncomatibleMsg(bean));
}
try {
setter.setIntercept(bean, value);
} catch (Exception ex) {
Expand Down Expand Up @@ -795,6 +825,9 @@ public Object getValue(EntityBean bean) {
}

public Object getValueIntercept(EntityBean bean) {
if (!checkPropertyAccess(bean)) {
return null;
}
try {
return getter.getIntercept(bean);
} catch (Exception ex) {
Expand Down
118 changes: 118 additions & 0 deletions ebean-test/src/test/java/org/tests/inheritance/TestPropertyAccess.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
package org.tests.inheritance;

import io.ebean.DB;
import io.ebean.plugin.ExpressionPath;
import org.junit.jupiter.api.Test;
import org.tests.model.basic.*;

import java.sql.Timestamp;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;

/**
* @author Roland Praml, FOCONIS AG
*/
public class TestPropertyAccess {


private ExpressionPath custCretime = DB.getDefault().pluginApi().beanType(Customer.class).expressionPath("cretime");
private ExpressionPath custName = DB.getDefault().pluginApi().beanType(Customer.class).expressionPath("name");
// Note: Animal.name is only present in "Cat" not in "Dog"
private ExpressionPath animalName = DB.getDefault().pluginApi().beanType(Animal.class).expressionPath("name");
private ExpressionPath productName = DB.getDefault().pluginApi().beanType(Product.class).expressionPath("name");
private ExpressionPath animalSpecies = DB.getDefault().pluginApi().beanType(Animal.class).expressionPath("species");

@Test
void testOnInheritance() {
Cat cat = new Cat();
cat.setName("Tom");
DB.save(cat);

Dog dog = new Dog();
dog.setRegistrationNumber("FOO");
DB.save(dog);


Animal animal = DB.find(Animal.class, cat.getId());
assertThat(animalName.pathGet(animal)).isEqualTo("Tom");

animal = DB.find(Animal.class, dog.getId());
assertThat(animalName.pathGet(animal)).isNull();

animalName.pathSet(cat, "Jerry");
assertThat(cat.getName()).isEqualTo("Jerry");

assertThatThrownBy(() -> animalName.pathSet(dog, "Jerry"))
.isInstanceOf(IllegalArgumentException.class);

animalSpecies.pathSet(cat, "Angora");
animalSpecies.pathSet(dog, "Bulldog");

assertThat(cat.getSpecies()).isEqualTo("Angora");
assertThat(dog.getSpecies()).isEqualTo("Bulldog");
}

@Test
void testOnMappedSuperClass() {
Customer cust = new Customer();

Timestamp ts = new Timestamp(123);
custCretime.pathSet(cust, ts);
assertThat(custCretime.pathGet(cust)).isEqualTo(ts);

custName.pathSet(cust, "Roland");
assertThat(custName.pathGet(cust)).isEqualTo("Roland");

}

@Test
void testOnPlainBean() {
Product product = new Product();

productName.pathSet(product, "Roland");
assertThat(productName.pathGet(product)).isEqualTo("Roland");
}

@Test
void testOnContactGroup() {
ContactGroup cg = new ContactGroup();

// CHECKEM: Ist it OK to us the "custCretime" on "contactGroup"
assertThatThrownBy(() -> custCretime.pathGet(cg)).isInstanceOf(IllegalArgumentException.class);
}

@Test
void testOnCrossUsage() {
Product product = new Product();
Customer cust = new Customer();
Cat cat = new Cat();
Dog dog = new Dog();


assertThatThrownBy(() -> custCretime.pathGet(product)).isInstanceOf(IllegalArgumentException.class);
custCretime.pathGet(cust);
assertThatThrownBy(() -> custCretime.pathGet(cat)).isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> custCretime.pathGet(dog)).isInstanceOf(IllegalArgumentException.class);

assertThatThrownBy(() -> custName.pathGet(product)).isInstanceOf(IllegalArgumentException.class);
custName.pathGet(cust);
assertThatThrownBy(() -> custName.pathGet(cat)).isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> custName.pathGet(dog)).isInstanceOf(IllegalArgumentException.class);

assertThatThrownBy(() -> animalName.pathGet(product)).isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> animalName.pathGet(cust)).isInstanceOf(IllegalArgumentException.class);
animalName.pathGet(cat);
animalName.pathGet(dog);

productName.pathGet(product);
assertThatThrownBy(() -> productName.pathGet(cust)).isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> productName.pathGet(cat)).isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> productName.pathGet(dog)).isInstanceOf(IllegalArgumentException.class);

assertThatThrownBy(() -> animalSpecies.pathGet(product)).isInstanceOf(IllegalArgumentException.class);
assertThatThrownBy(() -> animalSpecies.pathGet(cust)).isInstanceOf(IllegalArgumentException.class);
animalSpecies.pathGet(cat);
animalSpecies.pathGet(dog);
}
}