/**
   * Creates a Resolution object that holds a client value that represents the given domain value.
   * The resolved client value will be assignable to {@code clientType}.
   */
  private Resolution resolveClientValue(Object domainValue, Type clientType) {
    if (domainValue == null) {
      return new Resolution(null);
    }

    boolean anyType = clientType == null;
    if (anyType) {
      clientType = Object.class;
    }

    Class<?> assignableTo = TypeUtils.ensureBaseType(clientType);
    ResolutionKey key = new ResolutionKey(domainValue, clientType);

    Resolution previous = resolved.get(key);
    if (previous != null && assignableTo.isInstance(previous.getClientObject())) {
      return previous;
    }

    Class<?> returnClass = service.resolveClientType(domainValue.getClass(), assignableTo, true);

    if (anyType) {
      assignableTo = returnClass;
    }

    // Pass simple values through
    if (ValueCodex.canDecode(returnClass)) {
      return makeResolution(domainValue);
    }

    // Convert entities to EntityProxies or EntityProxyIds
    boolean isProxy = BaseProxy.class.isAssignableFrom(returnClass);
    boolean isId = EntityProxyId.class.isAssignableFrom(returnClass);
    if (isProxy || isId) {
      Class<? extends BaseProxy> proxyClass = returnClass.asSubclass(BaseProxy.class);
      return resolveClientProxy(domainValue, proxyClass, key);
    }

    // Convert collections
    if (Collection.class.isAssignableFrom(returnClass)) {
      Collection<Object> accumulator;
      if (List.class.isAssignableFrom(returnClass)) {
        accumulator = new ArrayList<Object>();
      } else if (Set.class.isAssignableFrom(returnClass)) {
        accumulator = new HashSet<Object>();
      } else {
        throw new ReportableException("Unsupported collection type" + returnClass.getName());
      }

      Type elementType = TypeUtils.getSingleParameterization(Collection.class, clientType);
      for (Object o : (Collection<?>) domainValue) {
        accumulator.add(resolveClientValue(o, elementType).getClientObject());
      }
      return makeResolution(accumulator);
    }

    throw new ReportableException("Unsupported domain type " + returnClass.getCanonicalName());
  }
 private PropertyResolver(Resolution resolution) {
   ResolutionKey key = resolution.getResolutionKey();
   this.domainEntity = key.getDomainObject();
   this.isOwnerValueProxy = state.isValueType(TypeUtils.ensureBaseType(key.requestedType));
   this.needsSimpleValues = resolution.needsSimpleValues();
   this.propertyRefs = resolution.takeWork();
 }