diff --git a/core/src/main/java/google/registry/persistence/EnumSetUserType.java b/core/src/main/java/google/registry/persistence/EnumSetUserType.java new file mode 100644 index 000000000..b8e24455d --- /dev/null +++ b/core/src/main/java/google/registry/persistence/EnumSetUserType.java @@ -0,0 +1,37 @@ +// Copyright 2020 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 java.util.HashSet; +import java.util.Set; + +/** Abstract Hibernate user type for storing/retrieving {@link Set>}. */ +public class EnumSetUserType> extends GenericCollectionUserType>> { + + @Override + Set> getNewCollection() { + return new HashSet>(); + } + + @Override + ArrayColumnType getColumnType() { + return ArrayColumnType.STRING; + } + + @Override + public Class returnedClass() { + return Set.class; + } +} diff --git a/core/src/main/java/google/registry/persistence/GenericCollectionUserType.java b/core/src/main/java/google/registry/persistence/GenericCollectionUserType.java index 62e3fd7e4..70ee13f98 100644 --- a/core/src/main/java/google/registry/persistence/GenericCollectionUserType.java +++ b/core/src/main/java/google/registry/persistence/GenericCollectionUserType.java @@ -66,7 +66,7 @@ public abstract class GenericCollectionUserType extends Mu if (rs.getArray(names[0]) != null) { T result = getNewCollection(); for (Object element : (Object[]) rs.getArray(names[0]).getArray()) { - result.add(element); + result.add(convertToElem(element)); } return result; } @@ -85,4 +85,14 @@ public abstract class GenericCollectionUserType extends Mu Array arr = st.getConnection().createArrayOf(getColumnType().getTypeName(), list.toArray()); st.setArray(index, arr); } + + /** + * Override this to convert an element value retrieved from the database to a different type. + * + *

This method is useful when encoding a java type to one of the types that can be used as an + * array element. + */ + protected Object convertToElem(Object columnValue) { + return columnValue; + } } diff --git a/core/src/test/java/google/registry/persistence/EnumSetUserTypeTest.java b/core/src/test/java/google/registry/persistence/EnumSetUserTypeTest.java new file mode 100644 index 000000000..50e90a944 --- /dev/null +++ b/core/src/test/java/google/registry/persistence/EnumSetUserTypeTest.java @@ -0,0 +1,79 @@ +// Copyright 2020 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.truth.Truth.assertThat; +import static google.registry.model.transaction.TransactionManagerFactory.jpaTm; + +import com.google.common.collect.ImmutableSet; +import google.registry.model.transaction.JpaTestRules; +import google.registry.model.transaction.JpaTestRules.JpaUnitTestRule; +import java.util.Set; +import javax.persistence.Entity; +import javax.persistence.Id; +import org.hibernate.annotations.Type; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +/** Unit tests for {@link EnumSetUserType}. */ +@RunWith(JUnit4.class) +public class EnumSetUserTypeTest { + @Rule + public final JpaUnitTestRule jpaRule = + new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule(); + + public EnumSetUserTypeTest() {} + + @Test + public void testRoundTrip() { + Set enums = ImmutableSet.of(TestEnum.BAR, TestEnum.FOO); + TestEntity obj = new TestEntity("foo", enums); + + jpaTm().transact(() -> jpaTm().getEntityManager().persist(obj)); + TestEntity persisted = + jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "foo")); + assertThat(persisted.data).isEqualTo(enums); + } + + enum TestEnum { + FOO, + BAR, + BAZ; + + public static class TestEnumType extends EnumSetUserType { + @Override + protected Object convertToElem(Object value) { + return TestEnum.valueOf((String) value); + } + } + } + + @Entity(name = "TestEntity") + static class TestEntity { + @Id String name; + + @Type(type = "google.registry.persistence.EnumSetUserTypeTest$TestEnum$TestEnumType") + Set data; + + TestEntity() {} + + TestEntity(String name, Set data) { + this.name = name; + this.data = data; + } + } +}