handel unboxing of null values
[idea/community.git] / java / debugger / impl / src / com / intellij / debugger / engine / evaluation / expression / UnBoxingEvaluator.java
1 /*
2  * Copyright 2000-2010 JetBrains s.r.o.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.intellij.debugger.engine.evaluation.expression;
17
18 import com.intellij.debugger.engine.DebugProcessImpl;
19 import com.intellij.debugger.engine.evaluation.EvaluateException;
20 import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
21 import com.intellij.openapi.util.Pair;
22 import com.intellij.util.containers.HashMap;
23 import com.sun.jdi.ClassType;
24 import com.sun.jdi.Method;
25 import com.sun.jdi.ObjectReference;
26 import com.sun.jdi.Value;
27 import org.jetbrains.annotations.Nullable;
28
29 import java.util.ArrayList;
30 import java.util.List;
31 import java.util.Map;
32
33 /**
34  * @author Eugene Zhuravlev
35  *         Date: Feb 8, 2010
36  */
37 public class UnBoxingEvaluator implements Evaluator{
38   private final Evaluator myOperand;
39   private static final Map<String, Pair<String, String>> TYPES_TO_CONVERSION_METHOD_MAP = new HashMap<String, Pair<String, String>>();
40   static {
41     TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Boolean", new Pair<String, String>("booleanValue", "()Z"));
42     TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Byte", new Pair<String, String>("byteValue", "()B"));
43     TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Character", new Pair<String, String>("charValue", "()C"));
44     TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Short", new Pair<String, String>("shortValue", "()S"));
45     TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Integer", new Pair<String, String>("intValue", "()I"));
46     TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Long", new Pair<String, String>("longValue", "()J"));
47     TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Float", new Pair<String, String>("floatValue", "()F"));
48     TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Double", new Pair<String, String>("doubleValue", "()D"));
49   }
50
51   public static boolean isTypeUnboxable(String typeName) {
52     return TYPES_TO_CONVERSION_METHOD_MAP.containsKey(typeName);
53   }
54
55   public UnBoxingEvaluator(Evaluator operand) {
56     myOperand = operand;
57   }
58
59   public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
60     final Value result = (Value)myOperand.evaluate(context);
61     if (result == null) {
62       throw new EvaluateException("java.lang.NullPointerException: cannot unbox null value");
63     }
64     if (result instanceof ObjectReference) {
65       final String valueTypeName = result.type().name();
66       final Pair<String, String> pair = TYPES_TO_CONVERSION_METHOD_MAP.get(valueTypeName);
67       if (pair != null) {
68         return convertToPrimitive(context, (ObjectReference)result, pair.getFirst(), pair.getSecond());
69       }
70     }
71     return result;
72   }
73                                           
74   @Nullable
75   public Modifier getModifier() {
76     return null;
77   }
78
79   private static Value convertToPrimitive(EvaluationContextImpl context, ObjectReference value, final String conversionMethodName,
80                                           String conversionMethodSignature) throws EvaluateException {
81     final DebugProcessImpl process = context.getDebugProcess();
82     final ClassType wrapperClass = (ClassType)value.referenceType();
83     final List<Method> methods = wrapperClass.methodsByName(conversionMethodName, conversionMethodSignature);
84     if (methods.size() == 0) { 
85       throw new EvaluateException("Cannot convert to primitive value of type " + value.type() + ": Unable to find method " +
86                                   conversionMethodName + conversionMethodSignature);
87     }
88
89     final Method method = methods.get(0);
90
91     return process.invokeMethod(context, value, method, new ArrayList());
92   }
93 }