23

私はを持っておりjava.lang.reflect.InvocationHandler、メソッドinvoke()を実装する必要があります

精緻化からの型の値がjava.lang.Stringあり、この値をメソッドで期待される適切なreturnTypeに変換する必要があります(int、boolean、doubleなどのプリミティブ、またはBoolean、Integer、Double、Floatなどのラッパークラスにすることができます) 。

例:

public Object invoke(Object proxy, Method method, Object[] args) 
        throws Throwable {
    String computedValue = compute(...);
    return convert(method.getReturnType(), computedValue);
}

private Object convert(Class<?> returnType, String stringValue) {
    return ...; // what's the simplest way?
}

複雑なオブジェクト間の自動変換を単純に実装することは期待していませんが、Stringから標準のJava型に変換する簡単な方法を期待しています。

私は(あまりにも)このようなものを何度も見ましたが、それは私には適切ではないようです:

public static Object toObject( Class clazz, String value ) {
    if( Boolean.class.isAssignableFrom( clazz ) ) return Boolean.parseBoolean( value );
    if( Byte.class.isAssignableFrom( clazz ) ) return Byte.parseByte( value );
    if( Short.class.isAssignableFrom( clazz ) ) return Short.parseShort( value );
    if( Integer.class.isAssignableFrom( clazz ) ) return Integer.parseInteger( value );
    if( Long.class.isAssignableFrom( clazz ) ) return Long.parseLong( value );
    if( Float.class.isAssignableFrom( clazz ) ) return Float.parseFloat( value );
    if( Double.class.isAssignableFrom( clazz ) ) return Double.parseDouble( value );
    return value;
}

そして、上記は私が今のところ見たものよりも悪いものではありません:)

誰かがここに秘密のトリックを持っていますか?

4

6 に答える 6

30

私の知る限り、あなたが提示したバージョンに代わるものはありません。(ラッパータイプがすべてであるため)少し単純化できますが、クラスをオンにするには、基本的にまたはまたはハッシュをfinal使用する必要があります。ifswitch

私のアドバイスは、上記のようにコーディングすることです。醜いコードは、それ自体を見なければならない場合にのみ問題になります。したがって、ユーティリティメソッド内に配置し、再度表示しないでください。


FWIW-これは私が方法を単純化する方法です:

public static Object toObject( Class clazz, String value ) {
    if( Boolean.class == clazz ) return Boolean.parseBoolean( value );
    if( Byte.class == clazz ) return Byte.parseByte( value );
    if( Short.class == clazz ) return Short.parseShort( value );
    if( Integer.class == clazz ) return Integer.parseInt( value );
    if( Long.class == clazz ) return Long.parseLong( value );
    if( Float.class == clazz ) return Float.parseFloat( value );
    if( Double.class == clazz ) return Double.parseDouble( value );
    return value;
}

これはより簡単で効率的です。また、クラスがすべてfinalであり、仕様ではオブジェクトの同等Class性がオブジェクトの同一性であると規定されているため、元のバージョンと同等です。

間違いなく、<wrapper>.valueOf(String)ラッパーオブジェクトを直接返すメソッドを使用する必要があります。

私はこれがそれほど醜くないとは主張しません...しかし、「美しさ」は主観的であり、コードが理解しやすいか、維持しやすいかを教えてくれないため、コード品質の有用な尺度ではありません。

アップデート

プリミティブ型もサポートするには、対応するクラスをif条件に追加します。例えば

    if (Boolean.class == clazz || Boolean.TYPE == clazz) {
        return Boolean.parseBoolean(value);
    }

タイプの名前で文字列スイッチを実行する方が効率的であるという点に到達している可能性がありますが、タイプIDには、検討する必要のあるわずかに厄介な問題がいくつかあります。(理論的には、異なるクラスローダーによってロードされた同じフルネームの複数のタイプを持つことができます。プリミティブラッパークラスでそれを行うには、クラスローダーで「高速かつ緩くプレイ」する必要があると思います...しかしそれでも可能かもしれないと思います。)

于 2012-12-19T00:15:34.677 に答える
26

私は何か見つけたと思う

import java.beans.PropertyEditor;
import java.beans.PropertyEditorManager;

@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    String returnValue = ...
    return convert(method.getReturnType(), returnValue); 
}

private Object convert(Class<?> targetType, String text) {
    PropertyEditor editor = PropertyEditorManager.findEditor(targetType);
    editor.setAsText(text);
    return editor.getValue();
}

これらの3行のコードは、複数のifよりも優れていると思います。また、java.beansパッケージはJava標準ライブラリ(javadocs :)内にあるため、外部ライブラリの依存関係を追加することは避けましたPropertyEditorManager

私はそれをかなり受け入れられると思います。私の唯一の困惑はそれPropertyEditorがパッケージに含まれていることであり、このコードは実際には何の関係もないので、またはパッケージでjava.beans利用可能なものを好むでしょう。java.utiljava.lang.reflectjava.beans

PropertyEditor上記のコードには、複雑なオブジェクトを変換するために追加のインスタンスを登録できるという利点もあります。しかし、それは悪いことではありません。

美しさだけでなく、品質の面でも、ifのリストよりも優れていると思います。

于 2012-12-19T09:33:25.940 に答える
7

おそらくorg.apache.commons.beanutils.ConvertUtilsが役に立ちますか?

import org.apache.commons.beanutils.ConvertUtils;
// ...
final Object v = ConvertUtils.convert("42", Integer.class);
于 2017-06-01T15:44:06.710 に答える
5

私はこれを提案します:

List<Class<?>> clsList = new ArrayList<Class<?>>();
clsList.add(Boolean.class);
clsList.add(Integer.class);
//etc.

for (Class<?> cls : clsList) {
    if (cls.isAssignableFrom(clazz)) {
        return cls.getMethod("valueOf", new Class[] { String.class }).invoke(null, new Object[] { value });
        //Missing in this example: Handle a few exceptions
    }
}

これがきれいに見えるか醜く見えるかはあなたに任せます。

于 2012-12-19T00:19:41.257 に答える
5

文字列をJavaタイプに解析して、必要な処理を実行する軽量のライブラリがあります。これはタイプパーサーと呼ばれ、ここのgithubで見つけることができます。

上記のコードは次のようになります。

public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    TypeParser parser = TypeParser.newBuilder().build();
    String computedValue = compute(...);
    return parser.parseType(computedValue,  method.getGenericReturnType());
}
于 2014-05-04T12:31:43.440 に答える
4

jdk8では、ifステートメントなしでO(1)ルックアップ時間のようなことを行うことができます...

nullを正しく処理するより良いバージョンはここにあります

https://github.com/deanhiller/webpieces/blob/master/webserver/http-router/src/main/java/org/webpieces/router/impl/params/ObjectTranslator.java

private Map<Class<?>, Function<String, Object>> classToUnmarshaller = new HashMap<>();
private Map<Class<?>, Function<Object, String>> classToMarshaller = new HashMap<>();

public ObjectTranslator() {
    classToUnmarshaller.put(Boolean.class, s -> s == null ? null : Boolean.parseBoolean(s));
    classToUnmarshaller.put(Boolean.TYPE, s -> Boolean.parseBoolean(s));
    classToUnmarshaller.put(Byte.class, s -> s == null ? null : Byte.parseByte(s));
    classToUnmarshaller.put(Byte.TYPE, s -> Byte.parseByte(s));
    classToUnmarshaller.put(Short.class, s -> s == null ? null : Short.parseShort(s));
    classToUnmarshaller.put(Short.TYPE, s -> Short.parseShort(s));
    classToUnmarshaller.put(Integer.class, s -> s == null ? null : Integer.parseInt(s));
    classToUnmarshaller.put(Integer.TYPE, s -> Integer.parseInt(s));
    classToUnmarshaller.put(Long.class, s -> s == null ? null : Long.parseLong(s));
    classToUnmarshaller.put(Long.TYPE, s -> Long.parseLong(s));
    classToUnmarshaller.put(Float.class, s -> s == null ? null : Float.parseFloat(s));
    classToUnmarshaller.put(Float.TYPE, s -> Float.parseFloat(s));
    classToUnmarshaller.put(Double.class, s -> s == null ? null : Double.parseDouble(s));
    classToUnmarshaller.put(Double.TYPE, s -> Double.parseDouble(s));
    classToUnmarshaller.put(String.class, s -> s);

    classToMarshaller.put(Boolean.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Boolean.TYPE, s -> s.toString());
    classToMarshaller.put(Byte.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Byte.TYPE, s -> s.toString());
    classToMarshaller.put(Short.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Short.TYPE, s -> s.toString());
    classToMarshaller.put(Integer.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Integer.TYPE, s -> s.toString());
    classToMarshaller.put(Long.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Long.TYPE, s -> s.toString());
    classToMarshaller.put(Float.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Float.TYPE, s -> s.toString());
    classToMarshaller.put(Double.class, s -> s == null ? null : s.toString());
    classToMarshaller.put(Double.TYPE, s -> s.toString());
    classToMarshaller.put(String.class, s -> s == null ? null : s.toString());
}

public Function<String, Object> getUnmarshaller(Class<?> paramTypeToCreate) {
    return classToUnmarshaller.get(paramTypeToCreate);
}

public Function<Object, String> getMarshaller(Class<?> type) {
    return classToMarshaller.get(type);
}

あなたがそれから呼び出すことができるように

primitiveTranslator.getConverter(Integer.TYPE).apply(stringToConvert);
于 2016-06-14T02:26:09.077 に答える