mirror of
https://github.com/google/nomulus.git
synced 2025-08-16 06:24:07 +02:00
Fix accessing superclass fields in checkExists() (#799)
* Fix accessing superclass fields in checkExists() JpaTransactionManagerImpl doesn't respect @Id fields in mapped superclasses. Replace calls to getDeclaredId() and getDeclaredField() with superclass friendly counterparts.
This commit is contained in:
parent
baa59b1f55
commit
86565f237d
2 changed files with 38 additions and 7 deletions
|
@ -391,7 +391,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||||
private static ImmutableSet<EntityId> getEntityIdsFromEntity(
|
private static ImmutableSet<EntityId> getEntityIdsFromEntity(
|
||||||
EntityType<?> entityType, Object entity) {
|
EntityType<?> entityType, Object entity) {
|
||||||
if (entityType.hasSingleIdAttribute()) {
|
if (entityType.hasSingleIdAttribute()) {
|
||||||
String idName = entityType.getDeclaredId(entityType.getIdType().getJavaType()).getName();
|
String idName = entityType.getId(entityType.getIdType().getJavaType()).getName();
|
||||||
Object idValue = getFieldValue(entity, idName);
|
Object idValue = getFieldValue(entity, idName);
|
||||||
return ImmutableSet.of(new EntityId(idName, idValue));
|
return ImmutableSet.of(new EntityId(idName, idValue));
|
||||||
} else {
|
} else {
|
||||||
|
@ -402,7 +402,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||||
private static ImmutableSet<EntityId> getEntityIdsFromSqlKey(
|
private static ImmutableSet<EntityId> getEntityIdsFromSqlKey(
|
||||||
EntityType<?> entityType, Object sqlKey) {
|
EntityType<?> entityType, Object sqlKey) {
|
||||||
if (entityType.hasSingleIdAttribute()) {
|
if (entityType.hasSingleIdAttribute()) {
|
||||||
String idName = entityType.getDeclaredId(entityType.getIdType().getJavaType()).getName();
|
String idName = entityType.getId(entityType.getIdType().getJavaType()).getName();
|
||||||
return ImmutableSet.of(new EntityId(idName, sqlKey));
|
return ImmutableSet.of(new EntityId(idName, sqlKey));
|
||||||
} else {
|
} else {
|
||||||
return getEntityIdsFromIdContainer(entityType, sqlKey);
|
return getEntityIdsFromIdContainer(entityType, sqlKey);
|
||||||
|
@ -429,7 +429,7 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||||
|
|
||||||
private static Object getFieldValue(Object object, String fieldName) {
|
private static Object getFieldValue(Object object, String fieldName) {
|
||||||
try {
|
try {
|
||||||
Field field = object.getClass().getDeclaredField(fieldName);
|
Field field = getField(object.getClass(), fieldName);
|
||||||
field.setAccessible(true);
|
field.setAccessible(true);
|
||||||
return field.get(object);
|
return field.get(object);
|
||||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
|
@ -437,6 +437,21 @@ public class JpaTransactionManagerImpl implements JpaTransactionManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Gets the field definition from clazz or any superclass. */
|
||||||
|
private static Field getField(Class clazz, String fieldName) throws NoSuchFieldException {
|
||||||
|
try {
|
||||||
|
// Note that we have to use getDeclaredField() for this, getField() just finds public fields.
|
||||||
|
return clazz.getDeclaredField(fieldName);
|
||||||
|
} catch (NoSuchFieldException e) {
|
||||||
|
Class base = clazz.getSuperclass();
|
||||||
|
if (base != null) {
|
||||||
|
return getField(base, fieldName);
|
||||||
|
} else {
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static class TransactionInfo {
|
private static class TransactionInfo {
|
||||||
EntityManager entityManager;
|
EntityManager entityManager;
|
||||||
boolean inTransaction = false;
|
boolean inTransaction = false;
|
||||||
|
|
|
@ -37,6 +37,8 @@ import java.util.List;
|
||||||
import java.util.NoSuchElementException;
|
import java.util.NoSuchElementException;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
import javax.persistence.Embeddable;
|
||||||
|
import javax.persistence.MappedSuperclass;
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
import org.junit.jupiter.api.TestTemplate;
|
import org.junit.jupiter.api.TestTemplate;
|
||||||
import org.junit.jupiter.api.extension.RegisterExtension;
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
@ -65,7 +67,7 @@ public class TransactionManagerTest {
|
||||||
.withClock(fakeClock)
|
.withClock(fakeClock)
|
||||||
.withDatastoreAndCloudSql()
|
.withDatastoreAndCloudSql()
|
||||||
.withOfyTestEntities(TestEntity.class)
|
.withOfyTestEntities(TestEntity.class)
|
||||||
.withJpaUnitTestEntities(TestEntity.class)
|
.withJpaUnitTestEntities(TestEntity.class, TestEntityBase.class)
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
TransactionManagerTest() {}
|
TransactionManagerTest() {}
|
||||||
|
@ -324,17 +326,31 @@ public class TransactionManagerTest {
|
||||||
entities.forEach(TransactionManagerTest::assertEntityNotExist);
|
entities.forEach(TransactionManagerTest::assertEntityNotExist);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We put the id field into a base class to test that id fields can be discovered in a base class.
|
||||||
|
*/
|
||||||
|
@MappedSuperclass
|
||||||
|
@Embeddable
|
||||||
|
private static class TestEntityBase extends ImmutableObject {
|
||||||
|
@Id @javax.persistence.Id protected String name;
|
||||||
|
|
||||||
|
TestEntityBase(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
TestEntityBase() {}
|
||||||
|
}
|
||||||
|
|
||||||
@Entity(name = "TxnMgrTestEntity")
|
@Entity(name = "TxnMgrTestEntity")
|
||||||
@javax.persistence.Entity(name = "TestEntity")
|
@javax.persistence.Entity(name = "TestEntity")
|
||||||
private static class TestEntity extends ImmutableObject {
|
private static class TestEntity extends TestEntityBase {
|
||||||
@Id @javax.persistence.Id private String name;
|
|
||||||
|
|
||||||
private String data;
|
private String data;
|
||||||
|
|
||||||
private TestEntity() {}
|
private TestEntity() {}
|
||||||
|
|
||||||
private TestEntity(String name, String data) {
|
private TestEntity(String name, String data) {
|
||||||
this.name = name;
|
super(name);
|
||||||
this.data = data;
|
this.data = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue