Merge pull request #2902 from forketyfork/master

BAEL-1280: Mapping Dynamic Values (@Formula, @Filter, @Any, @Where)
This commit is contained in:
lor6 2017-10-29 15:39:19 +02:00 committed by GitHub
commit 7f08f5164f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 431 additions and 17 deletions

View File

@ -22,13 +22,19 @@
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>5.2.9.Final</version>
<version>5.2.12.Final</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>3.8.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>

View File

@ -68,7 +68,7 @@ public class HibernateMultiTenantUtil {
Properties properties = new Properties();
URL propertiesURL = Thread.currentThread()
.getContextClassLoader()
.getResource("hibernate.properties");
.getResource("hibernate-multitenancy.properties");
FileInputStream inputStream = new FileInputStream(propertiesURL.getFile());
properties.load(inputStream);
System.out.println("LOADED PROPERTIES FROM hibernate.properties");

View File

@ -1,24 +1,58 @@
package com.baeldung.hibernate;
import com.baeldung.hibernate.pojo.Employee;
import com.baeldung.hibernate.pojo.EntityDescription;
import com.baeldung.hibernate.pojo.Phone;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;
import java.io.FileInputStream;
import java.io.IOException;
import java.net.URL;
import java.util.Properties;
public class HibernateUtil {
private static SessionFactory sessionFactory;
private static final SessionFactory sessionFactory;
static {
try {
Configuration configuration = new Configuration().configure();
sessionFactory = configuration.buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
public static SessionFactory getSessionFactory() throws IOException {
if (sessionFactory == null) {
ServiceRegistry serviceRegistry = configureServiceRegistry();
sessionFactory = makeSessionFactory(serviceRegistry);
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
private static SessionFactory makeSessionFactory(ServiceRegistry serviceRegistry) {
MetadataSources metadataSources = new MetadataSources(serviceRegistry);
metadataSources.addPackage("com.baeldung.hibernate.pojo");
metadataSources.addAnnotatedClass(Employee.class);
metadataSources.addAnnotatedClass(Phone.class);
metadataSources.addAnnotatedClass(EntityDescription.class);
Metadata metadata = metadataSources.buildMetadata();
return metadata.getSessionFactoryBuilder()
.build();
}
private static ServiceRegistry configureServiceRegistry() throws IOException {
Properties properties = getProperties();
return new StandardServiceRegistryBuilder().applySettings(properties)
.build();
}
private static Properties getProperties() throws IOException {
Properties properties = new Properties();
URL propertiesURL = Thread.currentThread()
.getContextClassLoader()
.getResource("hibernate.properties");
try (FileInputStream inputStream = new FileInputStream(propertiesURL.getFile())) {
properties.load(inputStream);
}
return properties;
}
}

View File

@ -0,0 +1,87 @@
package com.baeldung.hibernate.pojo;
import org.hibernate.annotations.*;
import javax.persistence.Entity;
import javax.persistence.*;
import java.io.Serializable;
import java.util.HashSet;
import java.util.Set;
@Entity
@Where(clause = "deleted = false")
@FilterDef(name = "incomeLevelFilter", parameters = @ParamDef(name = "incomeLimit", type = "int"))
@Filter(name = "incomeLevelFilter", condition = "grossIncome > :incomeLimit")
public class Employee implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private long grossIncome;
private int taxInPercents;
private boolean deleted;
public long getTaxJavaWay() {
return grossIncome * taxInPercents / 100;
}
@Formula("grossIncome * taxInPercents / 100")
private long tax;
@OneToMany
@JoinColumn(name = "employee_id")
@Where(clause = "deleted = false")
private Set<Phone> phones = new HashSet<>(0);
public Employee() {
}
public Employee(long grossIncome, int taxInPercents) {
this.grossIncome = grossIncome;
this.taxInPercents = taxInPercents;
}
public Integer getId() {
return id;
}
public long getGrossIncome() {
return grossIncome;
}
public int getTaxInPercents() {
return taxInPercents;
}
public long getTax() {
return tax;
}
public void setId(Integer id) {
this.id = id;
}
public void setGrossIncome(long grossIncome) {
this.grossIncome = grossIncome;
}
public void setTaxInPercents(int taxInPercents) {
this.taxInPercents = taxInPercents;
}
public boolean getDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public Set<Phone> getPhones() {
return phones;
}
}

View File

@ -0,0 +1,55 @@
package com.baeldung.hibernate.pojo;
import org.hibernate.annotations.Any;
import javax.persistence.*;
import java.io.Serializable;
@Entity
public class EntityDescription implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String description;
@Any(
metaDef = "EntityDescriptionMetaDef",
metaColumn = @Column(name = "entity_type")
)
@JoinColumn(name = "entity_id")
private Serializable entity;
public EntityDescription() {
}
public EntityDescription(String description, Serializable entity) {
this.description = description;
this.entity = entity;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public Serializable getEntity() {
return entity;
}
public void setEntity(Serializable entity) {
this.entity = entity;
}
}

View File

@ -0,0 +1,50 @@
package com.baeldung.hibernate.pojo;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.io.Serializable;
@Entity
public class Phone implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private boolean deleted;
private String number;
public Phone() {
}
public Phone(String number) {
this.number = number;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public boolean isDeleted() {
return deleted;
}
public void setDeleted(boolean deleted) {
this.deleted = deleted;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
}

View File

@ -0,0 +1,9 @@
@AnyMetaDef(name = "EntityDescriptionMetaDef", metaType = "string", idType = "int",
metaValues = {
@MetaValue(value = "Employee", targetEntity = Employee.class),
@MetaValue(value = "Phone", targetEntity = Phone.class)
})
package com.baeldung.hibernate.pojo;
import org.hibernate.annotations.AnyMetaDef;
import org.hibernate.annotations.MetaValue;

View File

@ -0,0 +1,164 @@
package com.baeldung.hibernate;
import com.baeldung.hibernate.pojo.Employee;
import com.baeldung.hibernate.pojo.EntityDescription;
import com.baeldung.hibernate.pojo.Phone;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
public class DynamicMappingIntegrationTest {
private Session session;
private Transaction transaction;
@Before
public void setUp() throws IOException {
session = HibernateUtil.getSessionFactory().openSession();
transaction = session.beginTransaction();
session.createNativeQuery("delete from phone").executeUpdate();
session.createNativeQuery("delete from employee").executeUpdate();
transaction.commit();
transaction = session.beginTransaction();
}
@After
public void tearDown() {
transaction.rollback();
session.close();
}
@Test
public void givenEntity_whenFieldMappedWithFormula_thenFieldIsCalculated() {
Employee employee = new Employee(10_000L, 25);
assertThat(employee.getTaxJavaWay()).isEqualTo(2_500L);
session.save(employee);
session.flush();
session.clear();
employee = session.get(Employee.class, employee.getId());
assertThat(employee.getTax()).isEqualTo(2_500L);
}
@Test
public void givenEntityMappedWithWhere_whenDeletedIsTrue_thenEntityNotFetched() {
Employee employee = new Employee();
session.save(employee);
session.clear();
employee = session.find(Employee.class, employee.getId());
assertThat(employee).isNotNull();
employee.setDeleted(true);
session.flush();
employee = session.find(Employee.class, employee.getId());
assertThat(employee).isNotNull();
session.clear();
employee = session.find(Employee.class, employee.getId());
assertThat(employee).isNull();
}
@Test
public void givenCollectionMappedWithWhere_whenDeletedIsTrue_thenEntityNotFetched() {
Employee employee = new Employee();
Phone phone1 = new Phone("555-45-67");
Phone phone2 = new Phone("555-89-01");
employee.getPhones().add(phone1);
employee.getPhones().add(phone2);
session.save(phone1);
session.save(phone2);
session.save(employee);
session.flush();
session.clear();
employee = session.find(Employee.class, employee.getId());
assertThat(employee.getPhones()).hasSize(2);
employee.getPhones().iterator().next().setDeleted(true);
session.flush();
session.clear();
employee = session.find(Employee.class, employee.getId());
assertThat(employee.getPhones()).hasSize(1);
List<Phone> fullPhoneList = session.createQuery("from Phone").getResultList();
assertThat(fullPhoneList).hasSize(2);
}
@Test
public void givenFilterByIncome_whenIncomeLimitSet_thenFilterIsApplied() throws IOException {
session.save(new Employee(10_000, 25));
session.save(new Employee(12_000, 25));
session.save(new Employee(15_000, 25));
session.flush();
session.clear();
session.enableFilter("incomeLevelFilter")
.setParameter("incomeLimit", 11_000);
List<Employee> employees = session.createQuery("from Employee").getResultList();
assertThat(employees).hasSize(2);
Employee employee = session.get(Employee.class, 1);
assertThat(employee.getGrossIncome()).isEqualTo(10_000);
session.close();
session = HibernateUtil.getSessionFactory().openSession();
transaction = session.beginTransaction();
employees = session.createQuery("from Employee").getResultList();
assertThat(employees).hasSize(3);
}
@Test
public void givenMappingWithAny_whenDescriptionAddedToEntity_thenDescriptionCanReferAnyEntity() {
Employee employee = new Employee();
Phone phone1 = new Phone("555-45-67");
Phone phone2 = new Phone("555-89-01");
employee.getPhones().add(phone1);
employee.getPhones().add(phone2);
EntityDescription employeeDescription = new EntityDescription("Send to conference next year", employee);
EntityDescription phone1Description = new EntityDescription("Home phone (do not call after 10PM)", phone1);
EntityDescription phone2Description = new EntityDescription("Work phone", phone1);
session.save(phone1);
session.save(phone2);
session.save(employee);
session.save(employeeDescription);
session.save(phone1Description);
session.save(phone2Description);
session.flush();
session.clear();
List<EntityDescription> descriptions = session.createQuery("from EntityDescription").getResultList();
assertThat(Employee.class.isAssignableFrom(descriptions.get(0).getEntity().getClass())).isTrue();
assertThat(Phone.class.isAssignableFrom(descriptions.get(1).getEntity().getClass())).isTrue();
assertThat(Phone.class.isAssignableFrom(descriptions.get(2).getEntity().getClass())).isTrue();
}
}

View File

@ -0,0 +1,9 @@
hibernate.connection.driver_class=org.h2.Driver
hibernate.connection.url=jdbc:h2:mem:mydb1;DB_CLOSE_DELAY=-1
hibernate.connection.username=sa
hibernate.connection.autocommit=true
jdbc.password=
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.show_sql=true
hibernate.multiTenancy=DATABASE

View File

@ -6,4 +6,4 @@ jdbc.password=
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.show_sql=true
hibernate.multiTenancy=DATABASE
hibernate.hbm2ddl.auto=create-drop