class PropertyInfoKey {
    private final Class<?> initialType;
    private final String propertyName;
    private final Configuration configuration;

    PropertyInfoKey(Class<?> initialType, String propertyName, Configuration configuration) {
      this.initialType = initialType;
      this.propertyName = propertyName;
      this.configuration = configuration;
    }

    @Override
    public boolean equals(Object o) {
      if (this == o)
        return true;
      if (!(o instanceof PropertyInfoKey))
        return false;
      PropertyInfoKey other = (PropertyInfoKey) o;
      return initialType.equals(other.initialType) && propertyName.equals(other.propertyName)
          && configuration.equals(other.configuration);
    }

    @Override
    public int hashCode() {
      int result = 31 + initialType.hashCode();
      result = 31 * result + propertyName.hashCode();
      result = 31 * result + configuration.hashCode();
      return result;
    }
  }

  /**
   * Returns an accessor for the {@code accessorName}, else {@code null} if none exists.
   */
  static Accessor accessorFor(Class<?> type, String accessorName, InheritingConfiguration configuration) {
    PropertyInfoKey key = new PropertyInfoKey(type, accessorName, configuration);
    if (!ACCESSOR_CACHE.containsKey(key) && !FIELD_CACHE.containsKey(key)) {
      @SuppressWarnings("unchecked")
      Class<Object> uncheckedType = (Class<Object>) type;
      for (Entry<String, Accessor> entry : TypeInfoRegistry.typeInfoFor(uncheckedType, configuration).getAccessors().entrySet()) {
        if (entry.getValue().getMember() instanceof Method)
          accessorFor(type, (Method) entry.getValue().getMember(), configuration, entry.getKey());
        else if (entry.getValue().getMember() instanceof Field)
          fieldPropertyFor(type, (Field) entry.getValue().getMember(), configuration, entry.getKey());
      }
    }

    if (ACCESSOR_CACHE.containsKey(key))
      return ACCESSOR_CACHE.get(key);
    return FIELD_CACHE.get(key);
  }

  /**
   * Returns an Accessor for the given accessor method. The method must be externally validated to
   * ensure that it accepts zero arguments and does not return void.class.
   */
  static synchronized Accessor accessorFor(Class<?> type, Method method,
      Configuration configuration, String name) {
    PropertyInfoKey key = new PropertyInfoKey(type, name, configuration);
    Accessor accessor = ACCESSOR_CACHE.get(key);
    if (accessor == null) {
      accessor = new MethodAccessor(type, method, name);
      ACCESSOR_CACHE.put(key, accessor);
    }

    return accessor;
  }

  /**
   * Returns a FieldPropertyInfo instance for the given field.
   */
  static synchronized FieldPropertyInfo fieldPropertyFor(Class<?> type, Field field,
      Configuration configuration, String name) {<FILL_FUNCTION_BODY>

    PropertyInfoKey key = new PropertyInfoKey(type, name, configuration);
    FieldPropertyInfo fieldPropertyInfo = FIELD_CACHE.get(key);
    if (fieldPropertyInfo == null) {
      fieldPropertyInfo = new FieldPropertyInfo(type, field, name);
      FIELD_CACHE.put(key, fieldPropertyInfo);
    }

    return fieldPropertyInfo;
  
<no_super_class>