Comment convertir une chaîne en un type primitif ou en types wrapper java standard

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 .valueOf(Ssortingng) 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

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

 private Map, Function> classToUnmarshaller = new HashMap<>(); private Map, Function> 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(Ssortingng.class, s -> s); classToMarshaller.put(Boolean.class, s -> s == null ? null : s.toSsortingng()); classToMarshaller.put(Boolean.TYPE, s -> s.toSsortingng()); classToMarshaller.put(Byte.class, s -> s == null ? null : s.toSsortingng()); classToMarshaller.put(Byte.TYPE, s -> s.toSsortingng()); classToMarshaller.put(Short.class, s -> s == null ? null : s.toSsortingng()); classToMarshaller.put(Short.TYPE, s -> s.toSsortingng()); classToMarshaller.put(Integer.class, s -> s == null ? null : s.toSsortingng()); classToMarshaller.put(Integer.TYPE, s -> s.toSsortingng()); classToMarshaller.put(Long.class, s -> s == null ? null : s.toSsortingng()); classToMarshaller.put(Long.TYPE, s -> s.toSsortingng()); classToMarshaller.put(Float.class, s -> s == null ? null : s.toSsortingng()); classToMarshaller.put(Float.TYPE, s -> s.toSsortingng()); classToMarshaller.put(Double.class, s -> s == null ? null : s.toSsortingng()); classToMarshaller.put(Double.TYPE, s -> s.toSsortingng()); classToMarshaller.put(Ssortingng.class, s -> s == null ? null : s.toSsortingng()); } public Function getUnmarshaller(Class paramTypeToCreate) { return classToUnmarshaller.get(paramTypeToCreate); } public Function getMarshaller(Class type) { return classToMarshaller.get(type); } 

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.