A @DoNotHydrate annotation for toHydratedString

This is needed for a soon-to-be-submitted CL that changes
all Refs to Keys and therefore removes the logic in
toHydratedString that doesn't expand Keys. We need to be
able to tag types as unexpandable to avoid cycles. It
would be better to tag fields, not types, but that is a
much harder change and not currently needed by the use
case of the following CL, so for now this suffices.

While I am in here, add tests for all of the features
of toHydratedString.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=131618634
This commit is contained in:
cgoldfeder 2016-08-29 11:56:35 -07:00 committed by Ben McIlwain
parent d77dced024
commit 8059ab5c90
2 changed files with 129 additions and 1 deletions

View file

@ -17,6 +17,8 @@ package google.registry.model;
import static com.google.common.base.Functions.identity;
import static com.google.common.collect.Iterables.transform;
import static com.google.common.collect.Maps.transformValues;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
@ -25,6 +27,9 @@ import com.google.common.collect.Maps;
import com.googlecode.objectify.Ref;
import com.googlecode.objectify.annotation.Ignore;
import google.registry.model.domain.ReferenceUnion;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
@ -37,6 +42,12 @@ import javax.xml.bind.annotation.XmlTransient;
@XmlTransient
public abstract class ImmutableObject implements Cloneable {
/** Marker to indicate that {@link #toHydratedString} should not hydrate a field of this type. */
@Documented
@Retention(RUNTIME)
@Target(TYPE)
public static @interface DoNotHydrate {}
@Ignore
@XmlTransient
Integer hashCode;
@ -109,7 +120,10 @@ public abstract class ImmutableObject implements Cloneable {
} else if (input instanceof Ref) {
// Only follow references of type Ref, not of type Key (the latter deliberately used for
// references that should not be followed)
return apply(((Ref<?>) input).get());
Object target = ((Ref<?>) input).get();
return target != null && target.getClass().isAnnotationPresent(DoNotHydrate.class)
? input
: apply(target);
} else if (input instanceof Map) {
return transformValues((Map<?, ?>) input, this);
} else if (input instanceof Collection) {