4

Commons BeanUtils getMatchingAccessibleMethod は一致を見つけますが、最適な一致ではありません。

次の簡単な例を考えてみましょう。

public class TestReflection extends TestCase {

  public static class BeanA {
    private DataX data;
    public BeanA setData(DataX x) {
      System.out.println("setData x");
      return this;
    }
    public BeanA setData(DataY y) {
      System.out.println("setData y");
      return this;
    }
  }

  static class DataX {
  }
  static class DataY extends DataX {
  }
  static class DataZ extends DataY {
  }

  public void testPropertyUtils() {
    try {
      BeanA a = new BeanA();
      System.out.println("--- setters:");
      a.setData(new DataX());
      a.setData(new DataY());
      a.setData(new DataZ());
      System.out.println("--- invokeMethod");
      MethodUtils.invokeMethod(a, "setData", new DataZ());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}

(ヒント: invokeMethod は getMatchingAccessibleMethod を使用します)

上記のコード出力

--- setters:
setData x
setData y
setData y
--- invokeMethod
setData x

最後の行は「setData y」と言う必要があります。これは、DataZ オブジェクトで「setData」を呼び出すのに最も適しているのは、インターフェイスに DataY があるものである必要があるためです (setData(new DataZ()) と同様)。

可能な限り最適な一致を見つける方法はありますか、それとも自分でコーディングする必要がありますか?

4

1 に答える 1

2

MethodUtils.java でどのように機能するのか気になったので、中を調べてみました。どの方法を最適な組み合わせとして使用するかを決定するために、すべての方法にコストがかかります。コストを計算するには、次の方法があります (余分な dbg 出力があります)。

/**
 * Gets the number of steps required needed to turn the source class into the 
 * destination class. This represents the number of steps in the object hierarchy 
 * graph.
 * @param srcClass The source class
 * @param destClass The destination class
 * @return The cost of transforming an object
 */
private static float getObjectTransformationCost(Class srcClass, Class destClass) {
    System.out.println("----------- start calculate cost from " + srcClass + " to " + destClass + "------------");

    float cost = 0.0f;
    while (destClass != null && !destClass.equals(srcClass)) {
        System.out.println(srcClass + " and " + destClass + " are " + (destClass.equals(srcClass)? " equal" : " not equal"));
        if (destClass.isInterface() && isAssignmentCompatible(destClass,srcClass)) {
            // slight penalty for interface match. 
            // we still want an exact match to override an interface match, but  
            // an interface match should override anything where we have to get a 
            // superclass.
            cost += 0.25f;
            break;
        }
        cost++;

        destClass = destClass.getSuperclass();
    }

    /*
     * If the destination class is null, we've travelled all the way up to 
     * an Object match. We'll penalize this by adding 1.5 to the cost.
     */
    if (destClass == null) {
        cost += 1.5f;
    }
    System.out.println("COST IS " + cost);


    return cost;
}

出力は

--- setters:
setData x
setData y
setData y
--- invokeMethod
----------- start calculate cost from class Lolka$DataZ to class Lolka$DataX------------
class Lolka$DataZ and class Lolka$DataX are  not equal
class Lolka$DataZ and class java.lang.Object are  not equal
COST IS 3.5
----------- start calculate cost from class Lolka$DataZ to class Lolka$DataY------------
class Lolka$DataZ and class Lolka$DataY are  not equal
class Lolka$DataZ and class Lolka$DataX are  not equal
class Lolka$DataZ and class java.lang.Object are  not equal
COST IS 4.5
setData x

したがって、invokeMethode は、DataX の変換が 1 つの継承レベル フォーム オブジェクトであり、DataY が 2 であると想定します。したがって、DataX メソッドは「安価」です。それがその背後にあるロジックです。

UPD: dest を src に変更しても問題なく動作するので、

private static float getObjectTransformationCost(Class srcClass, Class destClass) {
    float cost = 0.0f;
    while (srcClass != null && !destClass.equals(srcClass)) {
        if (destClass.isInterface() && isAssignmentCompatible(destClass,srcClass)) {
            cost += 0.25f;
            break;
        }
        cost++;

        srcClass = srcClass.getSuperclass();
    }

    if (srcClass == null) {
        cost += 1.5f;
    }

    return cost;
}

出力は

--- setters:
setData x
setData y
setData y
--- invokeMethod
setData y
于 2012-06-28T10:40:57.763 に答える