1
0
mirror of https://github.com/google/nomulus synced 2026-06-09 16:33:02 +00:00

Compare commits

..

2 Commits

Author SHA1 Message Date
Weimin Yu ce80278ab7 Make Gradle dependency cache shareable in GCB (#479)
* Make Gradle dependency cache shareable in GCB

Make Gradle put its caches in the source tree so that
they can be preserved across steps. When left at their
default location, caches are lost after each step.
2020-02-10 11:20:11 -05:00
Shicong Huang 594ce30122 Auto-apply JPA converters for collection type (#469)
* Auto-apply JPA converters for collection type

* Extract common logic to a base class

* Remove extra lines

* Rebase on master
2020-02-10 10:33:43 -05:00
25 changed files with 418 additions and 262 deletions
+1
View File
@@ -97,6 +97,7 @@ nomulus.iws
!/gradle/wrapper/**/*.jar
.gradle/
**/build
cloudbuild-caches/
node_modules/**
/repos/
+1 -1
View File
@@ -22,7 +22,7 @@ import sys
import re
# We should never analyze any generated files
UNIVERSALLY_SKIPPED_PATTERNS = {"/build/", "/out/"}
UNIVERSALLY_SKIPPED_PATTERNS = {"/build/", "cloudbuild-caches", "/out/"}
# We can't rely on CI to have the Enum package installed so we do this instead.
FORBIDDEN = 1
REQUIRED = 2
@@ -53,7 +53,6 @@ import java.util.concurrent.ExecutionException;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
import org.joda.time.Duration;
@@ -117,7 +116,6 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
DateTime lastEppUpdateTime;
/** Status values associated with this resource. */
@Type(type = "google.registry.model.eppcommon.StatusValue$StatusValueSetType")
@Column(name = "statuses")
// TODO(mmuller): rename to "statuses" once we're off datastore.
Set<StatusValue> status;
@@ -185,7 +185,6 @@ public class DomainBase extends EppResource
String idnTableName;
/** Fully qualified host names of this domain's active subordinate hosts. */
@org.hibernate.annotations.Type(type = "google.registry.persistence.StringSetUserType")
Set<String> subordinateHosts;
/** When this domain's registration will expire. */
@@ -25,7 +25,6 @@ import google.registry.model.domain.DomainBase;
import google.registry.model.host.HostResource;
import google.registry.model.translators.EnumToAttributeAdapter.EppEnum;
import google.registry.model.translators.StatusValueAdapter;
import google.registry.persistence.EnumSetUserType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
/**
@@ -166,6 +165,4 @@ public enum StatusValue implements EppEnum {
return StatusValue.valueOf(LOWER_CAMEL.to(UPPER_UNDERSCORE, nullToEmpty(xmlName)));
}
/** Hibernate type for sets of {@link StatusValue}. */
public static class StatusValueSetType extends EnumSetUserType<StatusValue> {}
}
@@ -262,15 +262,12 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
State state;
/** The set of TLDs which this registrar is allowed to access. */
// TODO(b/147908600): Investigate how to automatically apply user type
@org.hibernate.annotations.Type(type = "google.registry.persistence.StringSetUserType")
Set<String> allowedTlds;
/** Host name of WHOIS server. */
String whoisServer;
/** Base URLs for the registrar's RDAP servers. */
@org.hibernate.annotations.Type(type = "google.registry.persistence.StringSetUserType")
Set<String> rdapBaseUrls;
/**
@@ -298,7 +295,6 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
String failoverClientCertificateHash;
/** A whitelist of netmasks (in CIDR notation) which the client is allowed to connect from. */
@org.hibernate.annotations.Type(type = "google.registry.persistence.CidrAddressBlockListUserType")
List<CidrAddressBlock> ipAddressWhitelist;
/** A hashed password for EPP access. The hash is a base64 encoded SHA256 string. */
@@ -42,14 +42,12 @@ import google.registry.model.ImmutableObject;
import google.registry.model.JsonMapBuilder;
import google.registry.model.Jsonifiable;
import google.registry.model.annotations.ReportedOn;
import google.registry.persistence.EnumSetUserType;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.annotations.Type;
/**
* A contact for a Registrar. Note, equality, hashCode and comparable have been overridden to only
@@ -103,9 +101,6 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
this.displayName = display;
this.required = required;
}
/** Hibernate type for sets of {@link Type}. */
public static class RegistrarPocType extends EnumSetUserType<Type> {}
}
/** The name of the contact. */
@@ -127,8 +122,6 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
* Multiple types are used to associate the registrar contact with various mailing groups. This
* data is internal to the registry.
*/
@org.hibernate.annotations.Type(
type = "google.registry.model.registrar.RegistrarContact$Type$RegistrarPocType")
Set<Type> types;
/**
@@ -16,20 +16,24 @@ package google.registry.persistence;
import google.registry.util.CidrAddressBlock;
import java.util.List;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/**
* Hibernate {@link org.hibernate.usertype.UserType} for storing/retrieving {@link
* List<CidrAddressBlock>} objects.
* JPA {@link AttributeConverter} for storing/retrieving {@link List<CidrAddressBlock>} objects.
* TODO(shicong): Investigate if we can have one converter for any List type
*/
public class CidrAddressBlockListUserType extends StringListUserType<CidrAddressBlock> {
@Converter(autoApply = true)
public class CidrAddressBlockListConverter extends StringListConverterBase<CidrAddressBlock> {
@Override
protected CidrAddressBlock convertToElem(String columnValue) {
return columnValue == null ? null : CidrAddressBlock.create(columnValue);
String toString(CidrAddressBlock element) {
return element.toString();
}
@Override
protected String convertToColumn(CidrAddressBlock elementValue) {
return elementValue == null ? null : elementValue.toString();
CidrAddressBlock fromString(String value) {
return CidrAddressBlock.create(value);
}
}
@@ -1,51 +0,0 @@
// 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 google.registry.util.TypeUtils.TypeInstantiator;
import java.util.HashSet;
import java.util.Set;
/** Abstract Hibernate user type for storing/retrieving {@link Set<Enum<E>>}. */
public class EnumSetUserType<E extends Enum<E>>
extends GenericCollectionUserType<Set<E>, E, String> {
@Override
Set<E> getNewCollection() {
return new HashSet<>();
}
@Override
ArrayColumnType getColumnType() {
return ArrayColumnType.STRING;
}
@Override
public Class returnedClass() {
return Set.class;
}
@Override
protected E convertToElem(String columnValue) {
return columnValue == null
? null
: Enum.valueOf(new TypeInstantiator<E>(getClass()) {}.getExactType(), columnValue);
}
@Override
protected String convertToColumn(E elementValue) {
return elementValue == null ? null : elementValue.toString();
}
}
@@ -1,119 +0,0 @@
// 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 google.registry.util.TypeUtils.TypeInstantiator;
import java.sql.Array;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Collection;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Generic Hibernate user type to store/retrieve Java collection as an array in Cloud SQL.
*
* @param <T> the concrete {@link Collection} type of the entity field
* @param <E> the Java type of the element for the collection of the entity field
* @param <C> the JDBC supported type of the element in the DB column array
*/
public abstract class GenericCollectionUserType<T extends Collection<E>, E, C>
extends MutableUserType {
abstract T getNewCollection();
abstract ArrayColumnType getColumnType();
enum ArrayColumnType {
STRING(Types.ARRAY, "text");
final int typeCode;
final String typeName;
ArrayColumnType(int typeCode, String typeName) {
this.typeCode = typeCode;
this.typeName = typeName;
}
int getTypeCode() {
return typeCode;
}
String getTypeName() {
return typeName;
}
String getTypeDdlName() {
return typeName + "[]";
}
}
@Override
public Class returnedClass() {
return new TypeInstantiator<T>(getClass()) {}.getExactType();
}
@Override
public int[] sqlTypes() {
return new int[] {getColumnType().getTypeCode()};
}
@Override
public Object nullSafeGet(
ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
if (rs.getArray(names[0]) != null) {
T result = getNewCollection();
for (C element : (C[]) rs.getArray(names[0]).getArray()) {
result.add(convertToElem(element));
}
return result;
}
return null;
}
@Override
public void nullSafeSet(
PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
if (value == null) {
st.setArray(index, null);
return;
}
T collection = (T) value;
Array arr =
st.getConnection()
.createArrayOf(
getColumnType().getTypeName(),
collection.stream().map(this::convertToColumn).toArray());
st.setArray(index, arr);
}
/**
* Override this to convert an element value retrieved from the database to a different type.
*
* <p>This method is useful when encoding a java type to one of the types that can be used as an
* array element.
*/
protected E convertToElem(C columnValue) {
return (E) columnValue;
}
protected C convertToColumn(E elementValue) {
return (C) elementValue;
}
}
@@ -13,9 +13,10 @@
// limitations under the License.
package google.registry.persistence;
import google.registry.persistence.GenericCollectionUserType.ArrayColumnType;
import java.sql.Types;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.dialect.PostgreSQL95Dialect;
import org.hibernate.service.ServiceRegistry;
/** Nomulus mapping rules for column types in Postgresql. */
public class NomulusPostgreSQLDialect extends PostgreSQL95Dialect {
@@ -25,8 +26,15 @@ public class NomulusPostgreSQLDialect extends PostgreSQL95Dialect {
registerColumnType(Types.TIMESTAMP_WITH_TIMEZONE, "timestamptz");
registerColumnType(Types.TIMESTAMP, "timestamptz");
registerColumnType(Types.OTHER, "hstore");
for (ArrayColumnType arrayType : ArrayColumnType.values()) {
registerColumnType(arrayType.getTypeCode(), arrayType.getTypeDdlName());
}
registerColumnType(
StringCollectionDescriptor.COLUMN_TYPE, StringCollectionDescriptor.COLUMN_DDL_NAME);
}
@Override
public void contributeTypes(
TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes(typeContributions, serviceRegistry);
typeContributions.contributeJavaTypeDescriptor(new StringCollectionDescriptor());
typeContributions.contributeSqlTypeDescriptor(new StringCollectionDescriptor());
}
}
@@ -0,0 +1,34 @@
// 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 google.registry.model.registrar.RegistrarContact.Type;
import java.util.Set;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/** JPA {@link AttributeConverter} for storing/retrieving {@link Set<Type>}. */
@Converter(autoApply = true)
public class RegistrarPocSetConverter extends StringSetConverterBase<Type> {
@Override
String toString(Type element) {
return element.name();
}
@Override
Type fromString(String value) {
return Type.valueOf(value);
}
}
@@ -0,0 +1,35 @@
// 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 google.registry.model.eppcommon.StatusValue;
import java.util.Set;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/** JPA {@link AttributeConverter} for storing/retrieving {@link Set<StatusValue>}. */
@Converter(autoApply = true)
public class StatusValueSetConverter extends StringSetConverterBase<StatusValue> {
@Override
String toString(StatusValue element) {
return element.name();
}
@Override
StatusValue fromString(String value) {
return StatusValue.valueOf(value);
}
}
@@ -0,0 +1,187 @@
// 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 google.registry.persistence.StringCollectionDescriptor.StringCollection;
import com.google.common.collect.ImmutableList;
import java.sql.Array;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Collection;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.spi.JdbcRecommendedSqlTypeMappingContext;
import org.hibernate.type.descriptor.sql.BasicBinder;
import org.hibernate.type.descriptor.sql.BasicExtractor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
/**
* The {@link JavaTypeDescriptor} and {@link SqlTypeDescriptor} for {@link StringCollection}.
*
* <p>A {@link StringCollection} object is a simple wrapper for a {@link Collection<String>} which
* can be stored as a string array in the database. The {@link JavaTypeDescriptor} and {@link
* SqlTypeDescriptor} is used by JPA/Hibernate to map between the collection and {@link Array} which
* is the actual type that JDBC uses to read from and write to the database.
*
* @see <a
* href="https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#basic-jpa-convert">JPA
* 2.1 AttributeConverters</a>
*/
public class StringCollectionDescriptor extends AbstractTypeDescriptor<StringCollection>
implements SqlTypeDescriptor {
public static final int COLUMN_TYPE = Types.ARRAY;
public static final String COLUMN_NAME = "text";
public static final String COLUMN_DDL_NAME = COLUMN_NAME + "[]";
protected StringCollectionDescriptor() {
super(StringCollection.class);
}
@Override
public StringCollection fromString(String string) {
throw new UnsupportedOperationException(
"Constructing StringCollectionDescriptor from string is not allowed");
}
@Override
public <X> X unwrap(StringCollection value, Class<X> type, WrapperOptions options) {
if (value == null) {
return null;
}
if (Collection.class.isAssignableFrom(type)) {
return (X) value.getCollection();
}
throw unknownUnwrap(type);
}
@Override
public <X> StringCollection wrap(X value, WrapperOptions options) {
if (value == null) {
return null;
}
if (value instanceof Array) {
try {
String[] arr = (String[]) ((Array) value).getArray();
ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
for (String str : arr) {
builder.add(str);
}
return StringCollection.create(builder.build());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
throw unknownWrap(value.getClass());
}
@Override
public SqlTypeDescriptor getJdbcRecommendedSqlType(JdbcRecommendedSqlTypeMappingContext context) {
return this;
}
@Override
public int getSqlType() {
return COLUMN_TYPE;
}
@Override
public boolean canBeRemapped() {
return false;
}
@Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>(javaTypeDescriptor, this) {
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
throws SQLException {
if (value == null) {
st.setArray(index, null);
return;
}
if (value instanceof StringCollection) {
StringCollection stringCollection = (StringCollection) value;
if (stringCollection.getCollection() == null) {
st.setArray(index, null);
} else {
st.setArray(
index,
st.getConnection()
.createArrayOf(COLUMN_NAME, stringCollection.getCollection().toArray()));
}
} else {
throw new UnsupportedOperationException(
String.format(
"Binding type %s is not supported by StringCollectionDescriptor",
value.getClass().getName()));
}
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
// CallableStatement.setArray() doesn't have an overload version for setting array by its
// column name
throw new UnsupportedOperationException(
"Binding array by its column name is not supported");
}
};
}
@Override
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>(javaTypeDescriptor, this) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap(rs.getArray(name), options);
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options)
throws SQLException {
return javaTypeDescriptor.wrap(statement.getArray(index), options);
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
throws SQLException {
return javaTypeDescriptor.wrap(statement.getArray(name), options);
}
};
}
public static class StringCollection {
private Collection<String> collection;
private StringCollection(Collection<String> collection) {
this.collection = collection;
}
public static StringCollection create(Collection<String> collection) {
return new StringCollection(collection);
}
public Collection<String> getCollection() {
return collection;
}
}
}
@@ -14,19 +14,21 @@
package google.registry.persistence;
import com.google.common.collect.Lists;
import java.util.List;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/** Abstract Hibernate user type for storing/retrieving {@link List<String>}. */
public class StringListUserType<E> extends GenericCollectionUserType<List<E>, E, String> {
/** JPA {@link AttributeConverter} for storing/retrieving {@link List<String>}. */
@Converter(autoApply = true)
public class StringListConverter extends StringListConverterBase<String> {
@Override
List<E> getNewCollection() {
return Lists.newArrayList();
String toString(String element) {
return element;
}
@Override
ArrayColumnType getColumnType() {
return ArrayColumnType.STRING;
String fromString(String value) {
return value;
}
}
@@ -0,0 +1,48 @@
// 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.collect.ImmutableList.toImmutableList;
import google.registry.persistence.StringCollectionDescriptor.StringCollection;
import java.util.List;
import javax.persistence.AttributeConverter;
/**
* Base JPA converter for {@link List} objects that are stored as an array of strings in the
* database.
*/
public abstract class StringListConverterBase<T>
implements AttributeConverter<List<T>, StringCollection> {
abstract String toString(T element);
abstract T fromString(String value);
@Override
public StringCollection convertToDatabaseColumn(List<T> attribute) {
return attribute == null
? null
: StringCollection.create(
attribute.stream().map(this::toString).collect(toImmutableList()));
}
@Override
public List<T> convertToEntityAttribute(StringCollection dbData) {
return dbData == null || dbData.getCollection() == null
? null
: dbData.getCollection().stream().map(this::fromString).collect(toImmutableList());
}
}
@@ -14,19 +14,21 @@
package google.registry.persistence;
import com.google.common.collect.Sets;
import java.util.Set;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/** Abstract Hibernate user type for storing/retrieving {@link Set<String>}. */
public class StringSetUserType<E> extends GenericCollectionUserType<Set<E>, E, String> {
/** JPA {@link AttributeConverter} for storing/retrieving {@link Set<String>}. */
@Converter(autoApply = true)
public class StringSetConverter extends StringSetConverterBase<String> {
@Override
Set<E> getNewCollection() {
return Sets.newHashSet();
String toString(String element) {
return element;
}
@Override
ArrayColumnType getColumnType() {
return ArrayColumnType.STRING;
String fromString(String value) {
return value;
}
}
@@ -0,0 +1,47 @@
// 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.collect.ImmutableSet.toImmutableSet;
import google.registry.persistence.StringCollectionDescriptor.StringCollection;
import java.util.Set;
import javax.persistence.AttributeConverter;
/**
* Base JPA converter for {@link Set} objects that are stored as an array of strings in the
* database.
*/
public abstract class StringSetConverterBase<T>
implements AttributeConverter<Set<T>, StringCollection> {
abstract String toString(T element);
abstract T fromString(String value);
@Override
public StringCollection convertToDatabaseColumn(Set<T> attribute) {
return attribute == null
? null
: StringCollection.create(attribute.stream().map(this::toString).collect(toImmutableSet()));
}
@Override
public Set<T> convertToEntityAttribute(StringCollection dbData) {
return dbData == null || dbData.getCollection() == null
? null
: dbData.getCollection().stream().map(this::fromString).collect(toImmutableSet());
}
}
@@ -39,9 +39,14 @@
<!-- Customized type converters -->
<class>google.registry.persistence.BloomFilterConverter</class>
<class>google.registry.persistence.CidrAddressBlockListConverter</class>
<class>google.registry.persistence.CreateAutoTimestampConverter</class>
<class>google.registry.persistence.CurrencyUnitConverter</class>
<class>google.registry.persistence.DateTimeConverter</class>
<class>google.registry.persistence.RegistrarPocSetConverter</class>
<class>google.registry.persistence.StatusValueSetConverter</class>
<class>google.registry.persistence.StringListConverter</class>
<class>google.registry.persistence.StringSetConverter</class>
<class>google.registry.persistence.UpdateAutoTimestampConverter</class>
<class>google.registry.persistence.ZonedDateTimeConverter</class>
@@ -25,13 +25,12 @@ import google.registry.util.CidrAddressBlock;
import java.util.List;
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 CidrAddressBlockListUserType}. */
/** Unit tests for {@link CidrAddressBlockListConverter}. */
@RunWith(JUnit4.class)
public class CidrAddressBlockListUserTypeTest {
@Rule
@@ -59,7 +58,6 @@ public class CidrAddressBlockListUserTypeTest {
@Id String name = "id";
@Type(type = "google.registry.persistence.CidrAddressBlockListUserType")
List<CidrAddressBlock> addresses;
private TestEntity() {}
@@ -18,29 +18,27 @@ import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import com.google.common.collect.ImmutableSet;
import google.registry.model.eppcommon.StatusValue;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.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}. */
/** Unit tests for {@link StatusValueSetConverter}. */
@RunWith(JUnit4.class)
public class EnumSetUserTypeTest {
public class StatusValueSetConverterTest {
@Rule
public final JpaUnitTestRule jpaRule =
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
public EnumSetUserTypeTest() {}
@Test
public void testRoundTrip() {
Set<TestEnum> enums = ImmutableSet.of(TestEnum.BAR, TestEnum.FOO);
Set<StatusValue> enums = ImmutableSet.of(StatusValue.INACTIVE, StatusValue.PENDING_DELETE);
TestEntity obj = new TestEntity("foo", enums);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(obj));
@@ -49,45 +47,15 @@ public class EnumSetUserTypeTest {
assertThat(persisted.data).isEqualTo(enums);
}
@Test
public void testNativeQuery_succeeds() {
Set<TestEnum> enums = ImmutableSet.of(TestEnum.BAR, TestEnum.FOO);
TestEntity obj = new TestEntity("foo", enums);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(obj));
assertThat(
ImmutableSet.of(
getSingleResultFromNativeQuery(
"SELECT data[1] FROM \"TestEntity\" WHERE name = 'foo'"),
getSingleResultFromNativeQuery(
"SELECT data[2] FROM \"TestEntity\" WHERE name = 'foo'")))
.containsExactly("BAR", "FOO");
}
private static Object getSingleResultFromNativeQuery(String sql) {
return jpaTm()
.transact(() -> jpaTm().getEntityManager().createNativeQuery(sql).getSingleResult());
}
enum TestEnum {
FOO,
BAR,
BAZ;
public static class TestEnumType extends EnumSetUserType<TestEnum> {}
}
@Entity(name = "TestEntity")
static class TestEntity {
@Id String name;
@Type(type = "google.registry.persistence.EnumSetUserTypeTest$TestEnum$TestEnumType")
Set<TestEnum> data;
Set<StatusValue> data;
TestEntity() {}
TestEntity(String name, Set<TestEnum> data) {
TestEntity(String name, Set<StatusValue> data) {
this.name = name;
this.data = data;
}
@@ -26,15 +26,14 @@ import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NoResultException;
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 StringListUserType}. */
/** Unit tests for {@link StringListConverter}. */
@RunWith(JUnit4.class)
public class StringListUserTypeTest {
public class StringListConverterTest {
@Rule
public final JpaUnitTestRule jpaRule =
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
@@ -123,7 +122,6 @@ public class StringListUserTypeTest {
@Id String name = "id";
@Type(type = "google.registry.persistence.StringListUserType")
List<String> tlds;
private TestEntity() {}
@@ -24,15 +24,14 @@ import google.registry.persistence.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 StringSetUserType}. */
/** Unit tests for {@link StringSetConverter}. */
@RunWith(JUnit4.class)
public class StringSetUserTypeTest {
public class StringSetConverterTest {
@Rule
public final JpaUnitTestRule jpaRule =
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
@@ -70,7 +69,6 @@ public class StringSetUserTypeTest {
@Id String name = "id";
@Type(type = "google.registry.persistence.StringSetUserType")
Set<String> tlds;
private TestEntity() {}
+1
View File
@@ -115,6 +115,7 @@ spotless {
format 'misc', {
clearSteps()
target '**/*.gradle'
targetExclude '**/cloudbuild-caches/**'
trimTrailingWhitespace()
indentWithSpaces(2)
endWithNewline()
+7
View File
@@ -29,6 +29,13 @@ environment="$1"
dest="$2"
gcs_prefix="storage.googleapis.com/domain-registry-maven-repository"
# Let Gradle put its caches (dependency cache and build cache) in the source
# tree. This allows sharing of the caches between steps in a Cloud Build
# task. (See ./cloudbuild-nomulus.yaml, which calls this script in several
# steps). If left at their default location, the caches will be lost after
# each step.
export GRADLE_USER_HOME="./cloudbuild-caches"
if [ "${environment}" == tool ]
then
mkdir -p "${dest}"