2012-03-16 8 views
3

私はリフレクションを使用してgettersを別のクラスのセッターにマッピングしています。つまり、stuts1が主にtext(Strings)を表示するためにフォームクラスを使用していて、特定の値を保持するバックエンドタイプ。私は現在ゲッターとセッターの間でマッピングができていましたが、これは簡単でしたが、混合タイプに問題があります。私はsetterのパラメータ型を使用して、期待されるものを見ているので、ゲッターからオブジェクトの型を判断し、予想される型にどのようにキャストする必要があります。反射を使用しているときに、未知の型をJavaでどのようにマップしてキャストできますか?

など。

HomePageForm -> HomePageData 
Name="Alexei" -> String name; (Maps correctly) 
Age="22"  -> int age;  (Needs casting from string to int and visa-vera in reverse) 

次は、これまで事前に

/** 
    * Map the two given objects by reflecting the methods from the mapTo object and finding its setter methods. Then 
    * find the corresponding getter method in the mapFrom class and invoke them to obtain each attribute value. 
    * Finally invoke the setter method for the mapTo class to set the attribute value. 
    * 
    * @param mapFrom The object to map attribute values from 
    * @param mapTo The object to map attribute values to 
    */ 
    private void map(Object mapFrom, Object mapTo) { 
     Method [] methods = mapTo.getClass().getMethods(); 
     for (Method methodTo : methods) { 
      if (isSetter(methodTo)) { 
       try { 
        //The attribute to map to setter from getter 
        String attName = methodTo.getName().substring(3); 

        //Find the corresponding getter method to retrieve the attribute value from 
        Method methodFrom = mapFrom.getClass().getMethod("get" + attName, new Class<?>[0]); 

        //If the methodFrom is a valid getter, set the attValue 
        if (isGetter(methodFrom)) { 
         //Invoke the getter to get the attribute to set 
         Object attValue = methodFrom.invoke(mapFrom, new Object[0]); 

         Class<?> fromType = attValue.getClass(); 

         //Need to cast/parse type here 
         if (fromType != methodTo.getParameterTypes()[0]){ 
          //!!Do something to case/parse type!! 
         } //if 

         //Invoke the setter to set the attribute value 
         methodTo.invoke(mapTo, attValue); 
        } //if 
       } catch (Exception e) { 
        Logger.getLogger(Constants.APP_LOGGER).fine("Exception in DataFormMappingService.map: " 
                   + "IllegalArgumentException" + e.getMessage()); 
        continue; 
       } 
      } //if 
     } //for 
    } //map 

おかげで、 アレクセイ・ブルー私のコードです。

+0

Dozer(http://dozer.sourceforge.net/documentation/simpleproperty.html)は、この種のものを自動的に処理します。 – artbristol

答えて

0

:私は働いていましたループスルーされてマッピングされます。 parseメソッドは型をチェックし、標準のJava型で動作するObject.toString()に対してvalueOfメソッドを使用します。

乾杯、

アレクセイブルー。

1

私は反射のヒーローではありませんが、intは基本データ型で、attValueObjectです。それはObject

+0

こんにちはMolske私は問題は、呼び出しメソッドが展開され、オブジェクトをプリミティブ型しかし、22がintであるか長いであるかはわからないので、それを文字列として残すだけです。 –

+0

これをIntegerに変更しましたが、まだIllegalArgumentExceptionがスローされます。本質的にフォームからのオブジェクトが検索され、それがStringである場合、データオブジェクトはそれを内部使用のために整数/ intとみなします。整数に変換するには、Integer.valueOfを使用する必要があると思いますか? –

0

にキャストすることができるように

あなたはIntegerに年齢の種類を試してみて、変更することはできうん、@Molskeは上のスポットです。私はちょうどあなたのコードのクイックテストを実行し、私は例外を取得

if (fromType != methodTo.getParameterTypes()[0]) 

java.lang.AssertionError: expected:<class java.lang.Integer> but was:<int> 

代わりの問題はIntegerし、この比較するint戻り値を推進していますfromType、あなたがmethodFrom.getReturnType()に対して比較する場合、コードは動作するはずです:

if (methodFrom.getReturnType() != methodTo.getParameterTypes()[0]) 

ここでのテストですマッピング、フィルタは単純であるマッピングするための方法で構築されていたときにそれは基本的に私の最初の溶液よりもきれいだが

/** 
    * Map to given objects taking into account the inclusion and exclusion sets. 
    * 
    * @param mapFrom The object to map attribute values from 
    * @param mapTo The object to map attribute values to 
    */ 
    private void map(Object mapFrom, Object mapTo) 
    { 
     setMapFilter(mapFrom, mapTo); 

     for (Method sMethod : filterMap.keySet()) 
     {    
      try 
      { 
       //Find the corresponding getter method to retrieve the attribute value from 
       Method gMethod = filterMap.get(sMethod); 

       //Invoke the getter to get the attribute to set 
       Object attValue = gMethod.invoke(mapFrom, new Object[0]); 

       //Get the mapping types and check their compatibility, if incompatible convert attValue type to toType 
       Class<?> fromType = gMethod.getReturnType(); 
       Class<?> toType = sMethod.getParameterTypes()[0]; 

       if(!toType.isAssignableFrom(fromType) && Objects.isNotNull(attValue)) 
       { 
        attValue = parseType(attValue, toType); 
       } //if 

       //Invoke the setter to set the attribute value 
       sMethod.invoke(mapTo, attValue); 
      } 
      catch (IllegalArgumentException e) 
      { 
       Logger.getLogger(Constants.APP_LOGGER).fine("Exception in DataFormMappingService.map: " 
                  + "IllegalArgumentException " + e.getMessage()); 
       continue; 
      } 
      catch (IllegalAccessException e) 
      { 
       Logger.getLogger(Constants.APP_LOGGER).fine("Exception in DataFormMappingService.map: " 
                  + "IllegalAccessException " + e.getMessage()); 
       continue; 
      } 
      catch (InvocationTargetException e) 
      { 
       Logger.getLogger(Constants.APP_LOGGER).fine("Exception in DataFormMappingService.map: " 
                  + "InvocationTargetException " + e.getMessage()); 
       continue; 
      } 
     } //for each 
    } //map 

    /** 
    * Refactored method to parse an object, attValue, from it's unknown type to the type expected. 
    * 
    * @param attValue The attribute value to parse 
    * @param type  The type expected/to convert to 
    * @return   The attribute value in the expected type, null otherwise 
    */ 
    private Object parseType(Object attValue, Class<?> type) 
    { 
     Object newAttValue = null; 

     if (isLiteral(type)) 
     { 
      newAttValue = attValue.toString(); 
     } 
     else if (isByte(type)) 
     { 
      newAttValue = Byte.valueOf(attValue.toString()); 
     } 
     else if (isInt(type)) 
     { 
      newAttValue = Integer.valueOf(attValue.toString()); 
     } 
     else if (isShort(type)) 
     { 
      newAttValue = Short.valueOf(attValue.toString()); 
     } 
     else if (isLong(type)) 
     { 
      newAttValue = Long.valueOf(attValue.toString()); 
     } 
     else if (isFloat(type)) 
     { 
      newAttValue = Float.valueOf(attValue.toString()); 
     } 
     else if (isDouble(type)) 
     { 
      newAttValue = Double.valueOf(attValue.toString()); 
     } 
     else if (isBoolean(type)) 
     { 
      newAttValue = Boolean.valueOf(attValue.toString()); 
     } //if-else if* 

     return newAttValue; 
    } //parseType 

:私は最終的により良いソリューションを実装

@Test 
public void testException() throws Exception { 
    Foo foo = new Foo(); 
    Bar bar = new Bar(); 
    for (Method methodTo : Bar.class.getMethods()) { 
     if (methodTo.getName().startsWith("set")) { 
      String attName = methodTo.getName().substring(3); 
      Method methodFrom = Foo.class.getMethod("get" + attName); 
      if (methodFrom != null && methodFrom.getName().startsWith("get")) { 
       Object attValue = methodFrom.invoke(foo); 
       // this ignores the auto-boxing issues 
       assertEquals(methodFrom.getReturnType(), 
        methodTo.getParameterTypes()[0]); 
       methodTo.invoke(bar, attValue); 
      } 
     } 
    } 
} 
private static class Foo { 
    public int getFoo() { return 1; } 
} 
private static class Bar { 
    public void setFoo(int i) { System.out.println("i = " + i); } 
} 
+0

ねえ、グレイ、私は私が持っている問題とは少しはっきりしていないと思う。問題は、フォームとデータの間の型が同じでないことです。たとえば、FooのgetFooはStringを返し、setFooは同じままです。これは私のマッピング方法が少し分かれているところですが、今のところ私は小さなパーサメソッドを書いて、今はそのトリックを行っています。それはあまり動的なatmではありません –

関連する問題