97

getXXX プロパティと setXXX プロパティしか持たない非常に単純な Java オブジェクトがあるとします。このオブジェクトは値を処理するためだけに使用されます。基本的には、レコードまたはタイプ セーフ (かつパフォーマンスの高い) マップです。多くの場合、このオブジェクトをキーと値のペア (文字列またはタイプ セーフ) に変換するか、キーと値のペアからこのオブジェクトに変換する必要があります。

リフレクションまたはこの変換を行うコードを手動で作成する以外に、これを達成するための最良の方法は何ですか?

例として、ObjectMessage タイプを使用せずに (または受信メッセージを適切な種類のオブジェクトに変換せずに)、このオブジェクトを jms 経由で送信することが考えられます。

4

23 に答える 23

186

考えられる解決策はたくさんありますが、もう 1 つだけ追加しましょう。Jackson (JSON 処理ライブラリ) を使用して、次のような「json レス」変換を行います。

ObjectMapper m = new ObjectMapper();
Map<String,Object> props = m.convertValue(myBean, Map.class);
MyBean anotherBean = m.convertValue(props, MyBean.class);

(このブログエントリにはさらにいくつかの例があります)

基本的に、互換性のある型はすべて変換できます: 互換性があるということは、型から JSON に変換し、その JSON から結果の型に変換した場合、エントリが一致することを意味します (適切に構成されていれば、認識されないものを無視することもできます)。

マップ、リスト、配列、プリミティブ、Bean のような POJO など、予想されるケースでうまく機能します。

于 2010-01-10T23:30:06.510 に答える
56

常に apache commons beanutilsがありますが、もちろんボンネットの下でリフレクションを使用しています

于 2009-04-11T08:30:03.377 に答える
8

JavaオブジェクトをMapに変換するメソッドです

public static Map<String, Object> ConvertObjectToMap(Object obj) throws 
    IllegalAccessException, 
    IllegalArgumentException, 
    InvocationTargetException {
        Class<?> pomclass = obj.getClass();
        pomclass = obj.getClass();
        Method[] methods = obj.getClass().getMethods();


        Map<String, Object> map = new HashMap<String, Object>();
        for (Method m : methods) {
           if (m.getName().startsWith("get") && !m.getName().startsWith("getClass")) {
              Object value = (Object) m.invoke(obj);
              map.put(m.getName().substring(3), (Object) value);
           }
        }
    return map;
}

呼び方はこんな感じ

   Test test = new Test()
   Map<String, Object> map = ConvertObjectToMap(test);
于 2012-10-15T19:28:56.753 に答える
4

Java 8では、これを試すことができます:

public Map<String, Object> toKeyValuePairs(Object instance) {
    return Arrays.stream(Bean.class.getDeclaredMethods())
            .collect(Collectors.toMap(
                    Method::getName,
                    m -> {
                        try {
                            Object result = m.invoke(instance);
                            return result != null ? result : "";
                        } catch (Exception e) {
                            return "";
                        }
                    }));
}
于 2015-11-04T01:56:06.947 に答える
3

たとえばXStream+Jettisonを使用するJSONは、キーと値のペアを持つ単純なテキスト形式です。たとえば、他のプラットフォーム/言語とのJavaオブジェクト交換用のApacheActiveMQJMSメッセージブローカーによってサポートされています。

于 2009-04-11T16:56:44.000 に答える
3

リフレクションと Groovy を使用するだけです:

def Map toMap(object) {             
return object?.properties.findAll{ (it.key != 'class') }.collectEntries {
            it.value == null || it.value instanceof Serializable ? [it.key, it.value] : [it.key,   toMap(it.value)]
    }   
}

def toObject(map, obj) {        
    map.each {
        def field = obj.class.getDeclaredField(it.key)
        if (it.value != null) {
            if (field.getType().equals(it.value.class)){
                obj."$it.key" = it.value
            }else if (it.value instanceof Map){
                def objectFieldValue = obj."$it.key"
                def fieldValue = (objectFieldValue == null) ? field.getType().newInstance() : objectFieldValue
                obj."$it.key" = toObject(it.value,fieldValue) 
            }
        }
    }
    return obj;
}
于 2012-05-13T07:55:40.963 に答える
3

juffrou-reflectの BeanWrapperを使用します。非常に高性能です。

Bean をマップに変換する方法は次のとおりです。

public static Map<String, Object> getBeanMap(Object bean) {
    Map<String, Object> beanMap = new HashMap<String, Object>();
    BeanWrapper beanWrapper = new BeanWrapper(BeanWrapperContext.create(bean.getClass()));
    for(String propertyName : beanWrapper.getPropertyNames())
        beanMap.put(propertyName, beanWrapper.getValue(propertyName));
    return beanMap;
}

ジュフルーは自分で開発しました。オープンソースですので、ご自由に改変・改変してご利用ください。ご不明な点がございましたら、お気軽にお問い合わせください。

乾杯

カルロス

于 2013-06-15T16:40:42.937 に答える
2

最善の解決策は、ドーザーを使用することです。マッパーファイルに次のようなものが必要です。

<mapping map-id="myTestMapping">
  <class-a>org.dozer.vo.map.SomeComplexType</class-a>
  <class-b>java.util.Map</class-b>
</mapping> 

それだけです、残りはドーザーが担当します!!!

DozerドキュメントのURL

于 2009-06-02T17:22:45.640 に答える
2

Joda フレームワークを使用できます。

http://joda.sourceforge.net/

JodaProperties を利用します。ただし、これは、特定の方法で Bean を作成し、特定のインターフェイスを実装することを規定しています。ただし、リフレクションなしで、特定のクラスからプロパティ マップを返すことができます。サンプルコードは次のとおりです。

http://pbin.oogly.co.uk/listings/viewlistingdetail/0e78eb6c76d071b4e22bbcac748c57

于 2009-04-11T17:50:12.203 に答える
2

もちろん、可能な最も簡単な変換方法があります - まったく変換しません!

クラスで定義されたプライベート変数を使用する代わりに、インスタンスの値を格納する HashMap のみをクラスに含めます。

次に、getter と setter が HashMap との間で値を返したり設定したりします。- それはすでに地図です。

AOP の魔法を少し使えば、個々のゲッターとセッターを実際に記述することなく、各値の名前に固有のゲッターとセッターを引き続き使用できるようにすることで、Bean に固有の非柔軟性を維持することさえできます。

于 2014-07-31T19:00:36.263 に答える
2

各 getter および setter への呼び出しをハードコーディングしたくない場合は、リフレクションがこれらのメソッドを呼び出す唯一の方法です (ただし、難しいことではありません)。

問題のクラスをリファクタリングして、Properties オブジェクトを使用して実際のデータを保持し、各ゲッターとセッターに get/set を呼び出すだけにできますか? そうすれば、やりたいことに適した構造ができあがります。それらをキー値形式で保存およびロードするメソッドもあります。

于 2009-04-14T10:31:58.643 に答える
1

一般的な変換サービスを作成する必要があります! ジェネリックスを使用して型を自由に保ちます (したがって、すべてのオブジェクトを key=>value に変換して元に戻すことができます)。

どのフィールドをキーにする必要がありますか? Bean からそのフィールドを取得し、値マップにその他の非一時的な値を追加します。

帰りは至って簡単。key(x) を読み取り、最初にキーを書き込み、次にすべてのリスト エントリを新しいオブジェクトに書き込みます。

Bean のプロパティ名は、Apache Commons の beanutilsで取得できます。

于 2009-04-14T11:00:41.087 に答える
1

単純なオブジェクト ツリーからキー値リストへのマッピング (キーは、オブジェクトのルート要素から検査対象の葉までのドット パス記述) の場合、キー値リストへのツリー変換がオブジェクトから xml へのマッピング。XML ドキュメント内の各要素には定義された位置があり、パスに変換できます。したがって、 XStreamを基本的で安定した変換ツールとして採用し、階層的なドライバーとライターの部分を独自の実装に置き換えました。XStream には基本的なパス トラッキング メカニズムも付属しており、他の 2 つと組み合わせることで、タスクに適したソリューションに厳密に導きます。

于 2011-09-22T16:45:06.857 に答える
1

もう1つの可能な方法はhereです。

BeanWrapper は、プロパティ値を (個別または一括で) 設定および取得し、プロパティ記述子を取得し、プロパティをクエリして読み取り可能か書き込み可能かを判断する機能を提供します。

Company c = new Company();
 BeanWrapper bwComp = BeanWrapperImpl(c);
 bwComp.setPropertyValue("name", "your Company");
于 2012-07-01T19:39:49.613 に答える
1

本当にパフォーマンスが必要な場合は、コード生成ルートに進むことができます。

独自のリフレクションを行い、AspectJ ITD の mixin を構築することで、これを行うことができます。

または、Spring Roo を使用してSpring Roo Addonを作成することもできます。Roo アドオンは上記と同様のことを行いますが、Spring Roo を使用するすべてのユーザーが利用できるため、ランタイム アノテーションを使用する必要はありません。

私は両方をやった。人々は Spring Roo を馬鹿にしていますが、実際には、Spring Roo は Java の最も包括的なコード生成です。

于 2012-05-31T16:39:01.623 に答える
1

Jackson ライブラリの助けを借りて、タイプ String/integer/double のすべてのクラス プロパティと、Map クラス内のそれぞれの値を見つけることができました。(リフレクション API を使用せずに! )

TestClass testObject = new TestClass();
com.fasterxml.jackson.databind.ObjectMapper m = new com.fasterxml.jackson.databind.ObjectMapper();

Map<String,Object> props = m.convertValue(testObject, Map.class);

for(Map.Entry<String, Object> entry : props.entrySet()){
    if(entry.getValue() instanceof String || entry.getValue() instanceof Integer || entry.getValue() instanceof Double){
        System.out.println(entry.getKey() + "-->" + entry.getValue());
    }
}
于 2017-03-22T21:45:37.863 に答える