Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[master] Jakarta Persistence 3.2 new feature - java.lang.Record support in @Embedded parts 2.0 #2163

Merged
merged 2 commits into from
Jul 8, 2024
Merged
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
@@ -0,0 +1,34 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation
package org.eclipse.persistence.testing.tests.junit.policies;

import java.time.Instant;
import java.util.Objects;

public record NestedDetailRecord(float floatAttribute, Instant instantAttribute) {

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NestedDetailRecord that = (NestedDetailRecord) o;
return Float.compare(floatAttribute, that.floatAttribute) == 0 && Objects.equals(instantAttribute, that.instantAttribute);
}

@Override
public int hashCode() {
return Objects.hash(floatAttribute, instantAttribute);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation
package org.eclipse.persistence.testing.tests.junit.policies;

import java.util.Objects;

public record NestedMasterRecord(int intAttribute, String stringAttribute, NestedDetailRecord nestedDetailRecord) {

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NestedMasterRecord that = (NestedMasterRecord) o;
return intAttribute == that.intAttribute && Objects.equals(stringAttribute, that.stringAttribute) && Objects.equals(nestedDetailRecord, that.nestedDetailRecord);
}

@Override
public int hashCode() {
return Objects.hash(intAttribute, stringAttribute, nestedDetailRecord);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.tests.junit.policies;

import org.eclipse.persistence.descriptors.copying.RecordCopyPolicy;
import org.junit.Test;

import java.time.Instant;

import static org.junit.Assert.assertEquals;

public class RecordCopyPolicyTest {

private final int INT_ATTR = 1;
private final String STRING_ATTR = "abcde";
private final float FLOAT_ATTR = 1.1F;
private final Instant INSTANT_ATTR = Instant.parse("2024-05-27T10:15:30.00Z");

@Test
public void cloneNestedRecordTest() {
NestedDetailRecord nestedDetailRecord = new NestedDetailRecord(FLOAT_ATTR, INSTANT_ATTR);
NestedMasterRecord source = new NestedMasterRecord(INT_ATTR, STRING_ATTR, nestedDetailRecord);
RecordCopyPolicy recordCopyPolicy = new RecordCopyPolicy();
NestedMasterRecord clone = (NestedMasterRecord)recordCopyPolicy.buildClone(source, null);
assertEquals(source, clone);
}

@Test
public void cloneNestedRecordWithNullTest() {
NestedDetailRecord nestedDetailRecord = new NestedDetailRecord(FLOAT_ATTR, INSTANT_ATTR);
NestedMasterRecord source = new NestedMasterRecord(INT_ATTR, null, nestedDetailRecord);
RecordCopyPolicy recordCopyPolicy = new RecordCopyPolicy();
NestedMasterRecord clone = (NestedMasterRecord)recordCopyPolicy.buildClone(source, null);
assertEquals(source, clone);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.testing.tests.junit.policies;

import org.eclipse.persistence.internal.descriptors.RecordInstantiationPolicy;
import org.junit.Test;

import java.time.Instant;
import java.util.ArrayList;
import java.util.List;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;

public class RecordInstantiationPolicyTest {

private final float FLOAT_ATTR = 1.1F;
private final Instant INSTANT_ATTR = Instant.parse("2024-05-27T10:15:30.00Z");

@Test
public void newRecordTest() {
Class<NestedDetailRecord> clazz = NestedDetailRecord.class;
//Values order is important. It must be same as order of Record attributes.
List<Object> values = new ArrayList<>();
values.add(FLOAT_ATTR);
values.add(INSTANT_ATTR);
RecordInstantiationPolicy<NestedDetailRecord> recordInstantiationPolicy = new RecordInstantiationPolicy<>(clazz);
recordInstantiationPolicy.setValues(values);
NestedDetailRecord nestedDetailRecord = (NestedDetailRecord) recordInstantiationPolicy.buildNewInstance();
assertEquals(FLOAT_ATTR, nestedDetailRecord.floatAttribute(), 0);
assertEquals(INSTANT_ATTR, nestedDetailRecord.instantAttribute());
}

@Test
public void newRecordWithNullTest() {
Class<NestedDetailRecord> clazz = NestedDetailRecord.class;
//Values order is important. It must be same as order of Record attributes.
List<Object> values = new ArrayList<>();
values.add(FLOAT_ATTR);
values.add(null);
RecordInstantiationPolicy<NestedDetailRecord> recordInstantiationPolicy = new RecordInstantiationPolicy<>(clazz);
recordInstantiationPolicy.setValues(values);
NestedDetailRecord nestedDetailRecord = (NestedDetailRecord) recordInstantiationPolicy.buildNewInstance();
assertEquals(FLOAT_ATTR, nestedDetailRecord.floatAttribute(), 0);
assertNull(nestedDetailRecord.instantAttribute());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.eclipse.persistence.descriptors.copying.CopyPolicy;
import org.eclipse.persistence.descriptors.copying.InstantiationCopyPolicy;
import org.eclipse.persistence.descriptors.copying.PersistenceEntityCopyPolicy;
import org.eclipse.persistence.descriptors.copying.RecordCopyPolicy;
import org.eclipse.persistence.descriptors.invalidation.CacheInvalidationPolicy;
import org.eclipse.persistence.descriptors.invalidation.NoExpiryCacheInvalidationPolicy;
import org.eclipse.persistence.descriptors.partitioning.PartitioningPolicy;
Expand All @@ -73,6 +74,7 @@
import org.eclipse.persistence.internal.descriptors.PersistenceObject;
import org.eclipse.persistence.internal.descriptors.PersistenceObjectAttributeAccessor;
import org.eclipse.persistence.internal.descriptors.PersistenceObjectInstantiationPolicy;
import org.eclipse.persistence.internal.descriptors.RecordInstantiationPolicy;
import org.eclipse.persistence.internal.descriptors.SerializedObjectPolicyWrapper;
import org.eclipse.persistence.internal.descriptors.VirtualAttributeMethodInfo;
import org.eclipse.persistence.internal.dynamic.DynamicEntityImpl;
Expand Down Expand Up @@ -2123,7 +2125,11 @@ public List<Class<?>> getConstraintDependencies() {
public CopyPolicy getCopyPolicy() {
// Lazy initialize for XML deployment.
if (copyPolicy == null) {
setCopyPolicy(new InstantiationCopyPolicy());
if (javaClass != null && javaClass.isRecord()) {
setCopyPolicy(new RecordCopyPolicy());
} else {
setCopyPolicy(new InstantiationCopyPolicy());
}
}
return copyPolicy;
}
Expand Down Expand Up @@ -2308,7 +2314,11 @@ public InheritancePolicy getInheritancePolicyOrNull() {
public InstantiationPolicy getInstantiationPolicy() {
// Lazy initialize for XML deployment.
if (instantiationPolicy == null) {
setInstantiationPolicy(new InstantiationPolicy());
if (javaClass != null && javaClass.isRecord()) {
setInstantiationPolicy(new RecordInstantiationPolicy(javaClass));
} else {
setInstantiationPolicy(new InstantiationPolicy());
}
}
return instantiationPolicy;
}
Expand Down Expand Up @@ -3994,12 +4004,20 @@ public void preInitialize(AbstractSession session) throws DescriptorException {
}
if (!isMethodAccess) {
if (this.copyPolicy == null) {
setCopyPolicy(new PersistenceEntityCopyPolicy());
if (javaClass != null && javaClass.isRecord()) {
setCopyPolicy(new RecordCopyPolicy());
} else {
setCopyPolicy(new PersistenceEntityCopyPolicy());
}
}
if (!isAbstract()) {
try {
if (this.instantiationPolicy == null) {
setInstantiationPolicy(new PersistenceObjectInstantiationPolicy((PersistenceObject)getJavaClass().getConstructor().newInstance()));
if (javaClass != null && javaClass.isRecord()) {
setInstantiationPolicy(new RecordInstantiationPolicy(javaClass));
} else {
setInstantiationPolicy(new PersistenceObjectInstantiationPolicy((PersistenceObject)getJavaClass().getConstructor().newInstance()));
}
}
} catch (Exception ignore) { }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,8 @@ public void setDescriptor(ClassDescriptor descriptor) {
this.descriptor = descriptor;
}

@Override
public String toString() {
return getClass().getSimpleName() + "()";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,4 @@ public Object buildClone(Object domainObject, Session session) throws Descriptor
public boolean buildsNewInstance() {
return true;
}

@Override
public String toString() {
return getClass().getSimpleName() + "()";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,4 @@ public Object buildClone(Object object, Session session) throws DescriptorExcept
public boolean buildsNewInstance() {
return false;
}

@Override
public String toString() {
return getClass().getSimpleName() + "()";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2024 Oracle and/or its affiliates. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/

// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
package org.eclipse.persistence.descriptors.copying;

import org.eclipse.persistence.exceptions.DescriptorException;
import org.eclipse.persistence.sessions.Session;

import java.lang.reflect.Constructor;
import java.lang.reflect.RecordComponent;
import java.util.ArrayList;

/**
* <p><b>Purpose</b>: This is the copy policy for {@code java.lang.Record}.
* <p>
* It creates a copy by creating a new instance. As {@code java.lang.Record} is immutable
* all cloned attributes must be collected and passed to the constructor.
*/
public class RecordCopyPolicy extends AbstractCopyPolicy {
public RecordCopyPolicy() {
super();
}

@Override
public Object buildClone(Object domainObject, Session session) throws DescriptorException {
return cloneRecord((Record) domainObject);
}

@Override
public boolean buildsNewInstance() {
return true;
}

//There is limited functionality some complex nested objects shouldn't be cloned.
private <R extends Record> R cloneRecord(R template) {
try {
ArrayList<Class<?>> types = new ArrayList<>();
ArrayList<Object> values = new ArrayList<>();
for (RecordComponent component : template.getClass().getRecordComponents()) {
types.add(component.getType());
Object value = component.getAccessor().invoke(template);
if (value instanceof Record) {
value = cloneRecord((Record) value);
}
values.add(value);
}
Constructor<? extends Record> canonical = template.getClass().getDeclaredConstructor(types.toArray(Class[]::new));
@SuppressWarnings("unchecked")
var result = (R) canonical.newInstance(values.toArray(Object[]::new));
return result;
} catch (ReflectiveOperationException e) {
throw new RuntimeException("Record clone failed: " + e, e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
import org.eclipse.persistence.internal.core.sessions.CoreAbstractRecord;
import org.eclipse.persistence.internal.core.sessions.CoreAbstractSession;

import java.util.List;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove


public abstract class CoreObjectBuilder<
ABSTRACT_RECORD extends CoreAbstractRecord,
ABSTRACT_SESSION extends CoreAbstractSession,
Expand Down
Loading
Loading