Merge pull request #2380 from cit-consulting/isToManyDirty_cce

WIP: Try to fix ClassCastException in isToManyDirty() check
This commit is contained in:
Rob Bygrave
2021-09-22 14:00:19 +12:00
committed by GitHub
10 changed files with 297 additions and 3 deletions
@@ -2875,8 +2875,8 @@ public class BeanDescriptor<T> implements BeanType<T>, STreeType, SpiBeanType {
final EntityBeanIntercept ebi = bean._ebean_getIntercept();
for (BeanPropertyAssocMany<?> many : propertiesManySave) {
if (ebi.isLoadedProperty(many.propertyIndex())) {
final BeanCollection<?> value = (BeanCollection<?>) many.getValue(bean);
if (value != null && value.hasModifications()) {
final Object value = many.getValue(bean);
if (value instanceof BeanCollection && ((BeanCollection<?>)value).hasModifications() || value != null) {
return true;
}
}
@@ -13,6 +13,7 @@ import org.tests.model.basic.EBasicVer;
import org.tests.model.basic.Order;
import org.tests.model.basic.OrderShipment;
import java.util.ArrayList;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
@@ -176,6 +177,38 @@ public class TestTransparentPersist extends BaseTestCase {
DB.delete(Customer.class, c0.getId());
}
@Test
public void insertWithPersistCascadeInsert() {
// setup data
Customer c0 = new Customer();
c0.setName("firstCust");
DB.save(c0);
Integer orderId;
try (Transaction transaction = DB.beginTransaction()) {
transaction.setAutoPersistUpdates(true); // EXPERIMENTAL feature
Order order = new Order();
order.setStatus(Order.Status.NEW);
order.setCustomer(c0);
order.setShipments(new ArrayList<>());
DB.insert(order);
orderId = order.getId();
// cascade persist will insert this Shipment (even though it isn't in the persistence context)
OrderShipment osh0 = new OrderShipment();
order.addShipment(osh0);
transaction.commit();
}
Order checkOrder = DB.find(Order.class, orderId);
assertThat(checkOrder.getStatus()).isEqualTo(Order.Status.NEW);
assertThat(checkOrder.getShipments().size()).isEqualTo(1);
DB.delete(checkOrder);
DB.delete(Customer.class, c0.getId());
}
@Test
public void updateReferenceOnlyWithPersistCascade_Insert_andUpdateForeignKey() {
+1 -1
View File
@@ -17,7 +17,7 @@
<modules>
<module>test-java16</module>
<module>test-kotlin</module>
</modules>
</project>
+119
View File
@@ -0,0 +1,119 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.avaje</groupId>
<artifactId>java11-oss</artifactId>
<version>2.3</version>
</parent>
<name>kotlin test</name>
<description>Kotlin specific tests</description>
<artifactId>test-kotlin</artifactId>
<version>1.0</version>
<properties>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<ebean-maven-plugin.version>12.11.5</ebean-maven-plugin.version>
<kotlin.version>1.5.31</kotlin.version>
<jackson.version>2.12.1</jackson.version>
</properties>
<dependencies>
<dependency>
<groupId>io.avaje</groupId>
<artifactId>junit</artifactId>
<version>1.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-test</artifactId>
<version>12.11.6-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.ebean</groupId>
<artifactId>ebean-core</artifactId>
<version>12.11.6-SNAPSHOT</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-test</artifactId>
<version>${kotlin.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<testSourceDirectory>src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>${kotlin.version}</version>
<configuration>
<jvmTarget>11</jvmTarget>
</configuration>
<executions>
<execution>
<id>test-compile</id>
<goals>
<goal>test-compile</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>io.ebean</groupId>
<artifactId>ebean-maven-plugin</artifactId>
<version>${ebean-maven-plugin.version}</version>
<executions>
<execution>
<id>test</id>
<phase>process-test-classes</phase>
<configuration>
<transformArgs>debug=1</transformArgs>
</configuration>
<goals>
<goal>testEnhance</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- TODO remove. May be enable signing in release profile? -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.6</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>
@@ -0,0 +1,41 @@
package io.ebean.test.kotlin
import io.ebean.DB
import org.assertj.core.api.Assertions.assertThat
import org.example.order.Customer
import org.example.order.Order
import org.example.order.OrderItem
import org.junit.jupiter.api.Test
import java.math.BigDecimal
import kotlin.test.assertNotNull
class TransparentPersistenceTest {
@Test
fun `insert with cascade insert`() {
// setup data
// setup data
val c0 = Customer("Customer 0")
DB.save(c0)
var orderId: Long
DB.beginTransaction().use { transaction ->
transaction.setAutoPersistUpdates(true) // EXPERIMENTAL feature
val order = Order(c0)
DB.insert(order)
orderId = order.id
// cascade persist will insert this OrderItem (even though it isn't in the persistence context)
order.items.add(OrderItem(order, "item 0", BigDecimal.TEN))
transaction.commit()
}
val checkOrder = DB.find(Order::class.java, orderId)
assertNotNull(checkOrder)
assertThat(checkOrder.items.size).isEqualTo(1)
DB.delete(checkOrder)
DB.delete(c0)
}
}
@@ -0,0 +1,17 @@
package org.example.order
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.Version
@Entity
class Customer(
name: String,
) {
@Id
var id: Int = 0
val name: String = name
@Version
var version: Long = 0
}
@@ -0,0 +1,27 @@
package org.example.order
import javax.persistence.CascadeType
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.ManyToOne
import javax.persistence.OneToMany
import javax.persistence.Table
import javax.persistence.Version
@Entity
@Table(name = "t_order")
class Order(
customer: Customer,
) {
@Id
val id: Long = 0
@ManyToOne
val customer: Customer = customer
@OneToMany(mappedBy = "order", cascade = [CascadeType.ALL], orphanRemoval = true)
val items: MutableList<OrderItem> = mutableListOf()
@Version
val version: Long = 0
}
@@ -0,0 +1,29 @@
package org.example.order
import java.math.BigDecimal
import javax.persistence.Entity
import javax.persistence.Id
import javax.persistence.ManyToOne
@Entity
class OrderItem(
order: Order,
name: String,
price: BigDecimal,
amount: Int = 1,
description: String? = null,
) {
@Id
val id: Long = 0
@ManyToOne
val order: Order = order
val name: String = name
val description: String? = description
val amount: Int = amount
val price: BigDecimal = price
}
@@ -0,0 +1,6 @@
ebean:
test:
platform: h2
ddlMode: dropCreate
dbName: foo
@@ -0,0 +1,22 @@
<configuration scan="true" scanPeriod="10 seconds">
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
<pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>
<root level="INFO">
<appender-ref ref="STDOUT"/>
</root>
<logger name="org.avaje" level="TRACE"/>
<logger name="io.ebean" level="INFO"/>
<logger name="io.ebean.docker" level="TRACE"/>
<logger name="io.ebean.DDL" level="DEBUG"/>
<logger name="io.ebean.SQL" level="TRACE"/>
<logger name="io.ebean.TXN" level="TRACE"/>
<logger name="io.ebean.SUM" level="TRACE"/>
</configuration>