J’ai un java.lang.reflect.InvocationHandler
et je dois implémenter la méthode invoke ()
J’ai une valeur de type java.lang.Ssortingng
de mon élaboration et je dois convertir cette valeur dans le returnType approprié attendu par la méthode (il peut s’agir d’une primitive comme int, boolean, double ou wrapper comme Boolean, Integer, Double , Flotteur, etc).
Exemple:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Ssortingng computedValue = compute(...); return convert(method.getReturnType(), computedValue); } private Object convert(Class returnType, Ssortingng ssortingngValue) { return ...; // what's the simplest way? }
Je ne m’attends pas à implémenter simplement une conversion automatique entre des objects complexes, mais je m’attends à un moyen simple de convertir Ssortingng en types Java standard.
J’ai vu (trop) de nombreuses fois ce genre de choses, mais cela ne me semble pas approprié:
public static Object toObject( Class clazz, Ssortingng 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; }
et ce qui précède n’est même pas le pire que j’ai vu jusqu’à présent 🙂
Est-ce que quelqu’un a un truc secret ici?
Pour autant que je sache, il n’y a pas de réelle alternative à la version que vous avez présentée. Vous pouvez le simplifier un peu (puisque les types d’encapsuleurs sont tous final
), mais vous devez essentiellement utiliser if
switch
ou hachage pour activer la classe.
Mon conseil est de le coder comme ci-dessus. Un code laid n’est un problème en soi que si vous devez l’examiner. Donc, placez-le dans une méthode utilitaire et ne le regardez plus.
FWIW – Voici comment je simplifierais la méthode:
public static Object toObject( Class clazz, Ssortingng 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; }
C’est plus simple et plus efficace. Et il est équivalent à la version d’origine car les classes sont toutes final
et parce que les spécifications indiquent que l’égalité pour Class
objects de Class
est l’identité de l’object.
Nous pouvons sans doute utiliser les méthodes
qui renvoient directement les objects wrapper.
Je ne prétends pas que ce soit moins laid … mais la “beauté” n’est pas une mesure utile de la qualité du code, car elle est subjective et ne vous dit pas si le code est facile à comprendre et / ou à maintenir.
METTRE À JOUR
Pour prendre également en charge les types primitifs, ajoutez les classes correspondantes aux conditions if
. par exemple
if (Boolean.class == clazz || Boolean.TYPE == clazz) { return Boolean.parseBoolean(value); }
Il est peut-être maintenant plus efficace de faire passer un commutateur Ssortingng sur le nom du type, bien que certains problèmes légèrement épineux d’identité de type nécessitent une reflection approfondie. (En théorie, vous pouvez avoir plusieurs types avec le même nom complet qui ont été chargés par différents chargeurs de classes. Je pense que vous devrez “jouer vite et librement” dans un chargeur de classes pour faire cela avec les classes d’encapsulation primitives … mais Je pense que cela pourrait encore être possible.)
je pense avoir trouvé quelque chose
import java.beans.PropertyEditor; import java.beans.PropertyEditorManager; @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Ssortingng returnValue = ... return convert(method.getReturnType(), returnValue); } private Object convert(Class> targetType, Ssortingng text) { PropertyEditor editor = PropertyEditorManager.findEditor(targetType); editor.setAsText(text); return editor.getValue(); }
Je pense que ces 3 lignes de code sont meilleures que les multiples ifs, et j’ai évité d’append des dépendances de bibliothèque externes, car le package java.beans
est à l’intérieur des bibliothèques standard Java (javadocs: PropertyEditorManager
).
Je trouve cela tout à fait acceptable; Ma seule perplexité est que PropertyEditor
est contenu dans le package java.beans
et j’aurais préféré quelque chose de disponible dans le package java.util
ou java.lang.reflect
, car ce code n’a rien à voir avec java.beans
fait.
Le code ci-dessus présente également l’avantage de pouvoir enregistrer des instances supplémentaires de PropertyEditor
pour traduire des objects complexes, d’ailleurs. Ce n’est pas une mauvaise chose à avoir.
Je pense que c’est mieux qu’une liste de ifs, en beauté, mais aussi en qualité.
Probablement org.apache.commons.beanutils.ConvertUtils peut aider?
import org.apache.commons.beanutils.ConvertUtils; // ... final Object v = ConvertUtils.convert("42", Integer.class);
Il y a une bibliothèque légère qui parsing les chaînes en types Java qui font ce que vous voulez. Il s’appelle type-parser et vous pouvez le trouver sur github ici .
Votre code ci-dessus pourrait alors ressembler à ceci:
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { TypeParser parser = TypeParser.newBuilder().build(); Ssortingng computedValue = compute(...); return parser.parseType(computedValue, method.getGenericReturnType()); }
dans jdk8, vous pouvez maintenant faire quelque chose comme so O (1) temps de recherche sans instructions if si …
Une meilleure version maintenant qui gère NULL correct est ici
private Map, Function> classToUnmarshaller = new HashMap<>(); private Map, Function
de sorte que vous pouvez ensuite appeler
primitiveTranslator.getConverter(Integer.TYPE).apply(ssortingngToConvert);
Je propose ceci:
List> clsList = new ArrayList>(); clsList.add(Boolean.class); clsList.add(Integer.class); //etc. for (Class> cls : clsList) { if (cls.isAssignableFrom(clazz)) { return cls.getMethod("valueOf", new Class[] { Ssortingng.class }).invoke(null, new Object[] { value }); //Missing in this example: Handle a few exceptions } }
Je vous laisse le soin de savoir si cela a l’air plus propre ou plus laid.