Add a @GetterDelegate annotation for better handling of ImmutableObject fields (#2860)

This allows us to specify a getter delegation to bypass Hibernate's limitations
on field types for the purposes of, e.g., using a sorted set in toString()
output rather than the base Hibernate unsorted HashSet type.

BUG=http://b/448631639
This commit is contained in:
Ben McIlwain
2025-10-28 17:10:27 +00:00
committed by GitHub
parent c33f0dc07f
commit 8f69b48e87
7 changed files with 136 additions and 5 deletions
@@ -23,6 +23,7 @@ import static google.registry.testing.CertificateSamples.SAMPLE_CERT2_HASH;
import static google.registry.testing.CertificateSamples.SAMPLE_CERT_HASH;
import static google.registry.testing.DatabaseHelper.cloneAndSetAutoTimestamps;
import static google.registry.testing.DatabaseHelper.createTld;
import static google.registry.testing.DatabaseHelper.createTlds;
import static google.registry.testing.DatabaseHelper.newTld;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.testing.DatabaseHelper.persistResources;
@@ -760,4 +761,16 @@ class RegistrarTest extends EntityTestCase {
.setAllowedTlds(ImmutableSet.of("tld", "xn--q9jyb4c"))
.build();
}
@Test
void testToString_sortsAllowedTlds() {
createTlds("foo", "bar", "baz", "gon", "tri");
persistResource(
registrar
.asBuilder()
.setAllowedTlds(ImmutableSet.of("gon", "bar", "foo", "tri", "baz"))
.build());
assertThat(Registrar.loadByRegistrarId("registrar").toString())
.contains("allowedTlds=[bar, baz, foo, gon, tri]");
}
}
@@ -0,0 +1,52 @@
// Copyright 2025 The Nomulus Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package google.registry.persistence;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
import com.google.common.collect.ImmutableSet;
import google.registry.model.GetterDelegate;
import jakarta.persistence.Entity;
import java.lang.reflect.Field;
import org.junit.jupiter.api.Test;
/** Unit tests for Hibernate entities. */
public class EntitiesTest {
@Test
void getterDelegates_allMethodNamesExist() throws Exception {
ImmutableSet<Class<?>> entityClasses =
PersistenceXmlUtility.getManagedClasses().stream()
.filter(clazz -> clazz.isAnnotationPresent(Entity.class))
.collect(toImmutableSet());
for (Class<?> clazz : entityClasses) {
for (Field field : clazz.getDeclaredFields()) {
if (field.isAnnotationPresent(GetterDelegate.class)) {
String methodName = field.getAnnotation(GetterDelegate.class).methodName();
// Note that calling getDeclaredMethod(methodName) specifically looks for a method with
// no parameters; if there were a method that took e.g. one parameter, you'd need
// getDeclaredMethod(methodName, param1) to find it.
assertDoesNotThrow(
() -> clazz.getDeclaredMethod(methodName),
String.format(
"Method %s() specified in the GetterDelegate "
+ "annotation of field %s could not be found on class %s",
methodName, field.getName(), clazz.getCanonicalName()));
}
}
}
}
}
@@ -203,7 +203,9 @@ class ConsoleUpdateRegistrarActionTest extends ConsoleActionBaseTestCase {
"The following changes were made in registry unittest environment to the"
+ " registrar TheRegistrar by admin fte@email.tld:\n"
+ "\n"
+ "allowedTlds: null -> [app, dev]\n"
+ "allowedTlds:\n"
+ " ADDED: [app, dev]\n"
+ " FINAL CONTENTS: [app, dev]\n"
+ "lastPocVerificationDate: 1970-01-01T00:00:00.000Z ->"
+ " 2023-12-12T00:00:00.000Z\n")
.setRecipients(ImmutableList.of(new InternetAddress("notification@test.example")))