autoboxing support for debugger evaluators: binary/unary expressions, assignments...
authorEugene Zhuravlev <jeka@intellij.com>
Tue, 9 Feb 2010 12:30:36 +0000 (9 15:30 +0300)
committerEugene Zhuravlev <jeka@intellij.com>
Fri, 12 Feb 2010 16:30:47 +0000 (12 19:30 +0300)
java/debugger/impl/src/com/intellij/debugger/actions/SetValueAction.java
java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BoxingEvaluator.java [new file with mode: 0644]
java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/EvaluatorBuilderImpl.java
java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IdentityEvaluator.java [new file with mode: 0644]
java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnBoxingEvaluator.java [new file with mode: 0644]

index 2996a63..288275b 100644 (file)
@@ -20,9 +20,7 @@ import com.intellij.debugger.DebuggerInvocationUtil;
 import com.intellij.debugger.DebuggerManagerEx;
 import com.intellij.debugger.engine.ContextUtil;
 import com.intellij.debugger.engine.evaluation.*;
-import com.intellij.debugger.engine.evaluation.expression.EvaluatorBuilderImpl;
-import com.intellij.debugger.engine.evaluation.expression.ExpressionEvaluator;
-import com.intellij.debugger.engine.evaluation.expression.Modifier;
+import com.intellij.debugger.engine.evaluation.expression.*;
 import com.intellij.debugger.engine.events.DebuggerContextCommandImpl;
 import com.intellij.debugger.engine.events.SuspendContextCommandImpl;
 import com.intellij.debugger.impl.*;
@@ -225,6 +223,19 @@ public class SetValueAction extends DebuggerAction {
         value = context.getSuspendContext().getDebugProcess().getVirtualMachineProxy().mirrorOf((float)dValue);
       }
     }
+    if (value != null) {
+      if (varType instanceof PrimitiveType) {
+        if (!(value instanceof PrimitiveValue)) {
+          value = (Value)new UnBoxingEvaluator(new IdentityEvaluator(value)).evaluate(context);
+        }
+      }
+      else if (UnBoxingEvaluator.isTypeUnboxable(varType.name())) {
+        // variable is not primitive and boxing/unboxing is applicable
+        if (value instanceof PrimitiveValue) {
+          value = (Value)new BoxingEvaluator(new IdentityEvaluator(value)).evaluate(context);
+        }
+      }
+    }
     return value;
   }
 
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BoxingEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/BoxingEvaluator.java
new file mode 100644 (file)
index 0000000..060bc90
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.JVMNameUtil;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.sun.jdi.*;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Feb 8, 2010
+ */
+public class BoxingEvaluator implements Evaluator{
+  private final Evaluator myOperand;
+
+  public BoxingEvaluator(Evaluator operand) {
+    myOperand = operand;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    final Object result = myOperand.evaluate(context);
+    if (result == null || result instanceof ObjectReference) {
+      return result;
+    }
+
+    if (result instanceof BooleanValue) {
+      return convertToWrapper(context, (BooleanValue)result, "java.lang.Boolean");
+    }
+    if (result instanceof ByteValue) {
+      return convertToWrapper(context, (ByteValue)result, "java.lang.Byte");
+    }
+    if (result instanceof CharValue) {
+      return convertToWrapper(context, (CharValue)result, "java.lang.Character");
+    }
+    if (result instanceof ShortValue) {
+      return convertToWrapper(context, (ShortValue)result, "java.lang.Short");
+    }
+    if (result instanceof IntegerValue) {
+      return convertToWrapper(context, (IntegerValue)result, "java.lang.Integer");
+    }
+    if (result instanceof LongValue) {
+      return convertToWrapper(context, (LongValue)result, "java.lang.Long");
+    }
+    if (result instanceof FloatValue) {
+      return convertToWrapper(context, (FloatValue)result, "java.lang.Float");
+    }
+    if (result instanceof DoubleValue) {
+      return convertToWrapper(context, (DoubleValue)result, "java.lang.Double");
+    }
+    throw new EvaluateException("Cannot perform boxing conversion for a value of type " + ((Value)result).type().name());
+  }
+
+  @Nullable
+  public Modifier getModifier() {
+    return null;
+  }
+
+  private static Value convertToWrapper(EvaluationContextImpl context, PrimitiveValue value, String wrapperTypeName) throws
+                                                                                                                            EvaluateException {
+    final DebugProcessImpl process = context.getDebugProcess();
+    final ClassType wrapperClass = (ClassType)process.findClass(context, wrapperTypeName, null);
+    final String methodSignature = "(" + JVMNameUtil.getPrimitiveSignature(value.type().name()) + ")L" + wrapperTypeName.replace('.', '/') + ";";
+
+    List<Method> methods = wrapperClass.methodsByName("valueOf", methodSignature);
+    if (methods.size() == 0) { // older JDK version
+      methods = wrapperClass.methodsByName("<init>", methodSignature);
+    }
+    if (methods.size() == 0) {
+      throw new EvaluateException("Cannot construct wrapper object for value of type " + value.type() + ": Unable to find either valueOf() or constructor method");
+    }
+    
+    final Method factoryMethod = methods.get(0);
+
+    final ArrayList args = new ArrayList();
+    args.add(value);
+    
+    return process.invokeMethod(context, wrapperClass, factoryMethod, args);
+  }
+}
index 0e1f779..f3f1b3d 100644 (file)
@@ -20,6 +20,8 @@
  */
 package com.intellij.debugger.engine.evaluation.expression;
 
+import com.intellij.codeInsight.daemon.JavaErrorMessages;
+import com.intellij.codeInsight.daemon.impl.analysis.HighlightUtil;
 import com.intellij.debugger.DebuggerBundle;
 import com.intellij.debugger.SourcePosition;
 import com.intellij.debugger.engine.ContextUtil;
@@ -118,31 +120,40 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
 
     @Override
     public void visitAssignmentExpression(PsiAssignmentExpression expression) {
-      PsiExpression rExpression = expression.getRExpression();
-      if(rExpression == null) throw new EvaluateRuntimeException(EvaluateExceptionUtil
-        .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())));
+      final PsiExpression rExpression = expression.getRExpression();
+      if(rExpression == null) {
+        throw new EvaluateRuntimeException(
+          EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText()))
+        );
+      }
 
       rExpression.accept(this);
       Evaluator rEvaluator = myResult;
 
       if(expression.getOperationSign().getTokenType() != JavaTokenType.EQ) {
-        throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
-          DebuggerBundle.message("evaluation.error.operation.not.supported", expression.getOperationSign().getText())));
+        throw new EvaluateRuntimeException(
+          EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.operation.not.supported", expression.getOperationSign().getText()))
+        );
       }
 
-      PsiExpression lExpression = expression.getLExpression();
+      final PsiExpression lExpression = expression.getLExpression();
 
-      if(lExpression.getType() == null) {
-        throw new EvaluateRuntimeException(EvaluateExceptionUtil
-          .createEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", lExpression.getText())));
+      final PsiType lType = lExpression.getType();
+      if(lType == null) {
+        throw new EvaluateRuntimeException(
+          EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", lExpression.getText()))
+        );
       }
 
-      if(!TypeConversionUtil.areTypesAssignmentCompatible(lExpression.getType(), rExpression)) {
+      if(!TypeConversionUtil.areTypesAssignmentCompatible(lType, rExpression)) {
         throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.incompatible.types", expression.getOperationSign().getText())));
       }
       lExpression.accept(this);
       Evaluator lEvaluator = myResult;
 
+      if (TypeConversionUtil.boxingConversionApplicable(lType, rExpression.getType())) {
+        rEvaluator = (lType instanceof PsiPrimitiveType)? new UnBoxingEvaluator(rEvaluator) : new BoxingEvaluator(rEvaluator);
+      }
       myResult = new AssignmentEvaluator(lEvaluator, rEvaluator);
     }
 
@@ -266,9 +277,10 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
       if (LOG.isDebugEnabled()) {
         LOG.debug("visitBinaryExpression " + expression);
       }
-      expression.getLOperand().accept(this);
+      final PsiExpression lOperand = expression.getLOperand();
+      lOperand.accept(this);
       Evaluator lResult = myResult;
-      PsiExpression rOperand = expression.getROperand();
+      final PsiExpression rOperand = expression.getROperand();
       if(rOperand == null) {
         throw new EvaluateRuntimeException(EvaluateExceptionUtil
           .createEvaluateException(DebuggerBundle.message("evaluation.error.invalid.expression", expression.getText())));
@@ -280,6 +292,18 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
         throw new EvaluateRuntimeException(EvaluateExceptionUtil
           .createEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText())));
       }
+      // handle unboxing if neccesary
+      final PsiType lType = lOperand.getType();
+      final PsiType rType = rOperand.getType();
+      if (TypeConversionUtil.boxingConversionApplicable(lType, rType)) {
+        if (lType instanceof PsiPrimitiveType) {
+          myResult = new UnBoxingEvaluator(myResult);
+        }
+        else if (rType instanceof PsiPrimitiveType) {
+          lResult = new UnBoxingEvaluator(lResult);
+        }
+      }
+
       myResult = new BinaryExpressionEvaluator(lResult, myResult, opType, type.getCanonicalText());
     }
 
@@ -291,13 +315,13 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
       for (PsiElement declaredElement : declaredElements) {
         if (declaredElement instanceof PsiLocalVariable) {
           if (myCurrentFragmentEvaluator != null) {
-            PsiLocalVariable localVariable = ((PsiLocalVariable)declaredElement);
+            final PsiLocalVariable localVariable = ((PsiLocalVariable)declaredElement);
 
-            PsiType type = localVariable.getType();
+            final PsiType lType = localVariable.getType();
 
             PsiElementFactory elementFactory = JavaPsiFacade.getInstance(localVariable.getProject()).getElementFactory();
             try {
-              PsiExpression initialValue = elementFactory.createExpressionFromText(PsiTypesUtil.getDefaultValueOfType(type), null);
+              PsiExpression initialValue = elementFactory.createExpressionFromText(PsiTypesUtil.getDefaultValueOfType(lType), null);
               Object value = JavaConstantExpressionEvaluator.computeConstantExpression(initialValue, true);
               myCurrentFragmentEvaluator.setInitialValue(localVariable.getName(), value);
             }
@@ -315,6 +339,7 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
                   throw new EvaluateRuntimeException(EvaluateExceptionUtil.createEvaluateException(
                     DebuggerBundle.message("evaluation.error.incompatible.variable.initializer.type", localVariable.getName())));
                 }
+                final PsiType rType = initializer.getType();
                 initializer.accept(this);
                 Evaluator rEvaluator = myResult;
 
@@ -323,7 +348,16 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
                 localVarReference.accept(this);
                 Evaluator lEvaluator = myResult;
 
-                evaluators.add(new AssignmentEvaluator(lEvaluator, rEvaluator));
+                Evaluator assignment = new AssignmentEvaluator(lEvaluator, rEvaluator);
+                if (TypeConversionUtil.boxingConversionApplicable(lType, rType)) {
+                  if (lType instanceof PsiPrimitiveType) {
+                    assignment = new UnBoxingEvaluator(assignment);
+                  }
+                  else {
+                    assignment = new BoxingEvaluator(assignment);
+                  }
+                }
+                evaluators.add(assignment);
               }
               catch (IncorrectOperationException e) {
                 LOG.error(e);
@@ -602,8 +636,8 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
 
     @Override
     public void visitPrefixExpression(final PsiPrefixExpression expression) {
-      final PsiType type = expression.getType();
-      if(type == null) {
+      final PsiType expressionType = expression.getType();
+      if(expressionType == null) {
         throw new EvaluateRuntimeException(
           EvaluateExceptionUtil.createEvaluateException(DebuggerBundle.message("evaluation.error.unknown.expression.type", expression.getText()))
         );
@@ -616,6 +650,8 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
         );
       }
       
+      final PsiType operandExpressionType = operandExpression.getType();
+
       operandExpression.accept(this);
       final Evaluator operand = myResult;
 
@@ -628,10 +664,22 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
           PsiElementFactory elementFactory = JavaPsiFacade.getInstance(expression.getProject()).getElementFactory();
           PsiExpression one = elementFactory.createExpressionFromText("1", null);
           one.accept(this);
+          // handle unboxing issues
+          Evaluator left = operand;
+          if (!(operandExpressionType instanceof PsiPrimitiveType)) {
+            left = new UnBoxingEvaluator(left);
+          }
 
+          PsiType expected = expressionType;
+          final PsiPrimitiveType unboxedExpectedType = PsiPrimitiveType.getUnboxedType(expected);
+          if (unboxedExpectedType != null) {
+            expected = unboxedExpectedType;
+          }
+          final BinaryExpressionEvaluator rightEval = new BinaryExpressionEvaluator(
+            left, myResult, isPlus ? JavaTokenType.PLUS : JavaTokenType.MINUS, expected.getCanonicalText()
+          );
           myResult = new AssignmentEvaluator(
-            operand,
-            new BinaryExpressionEvaluator(operand, myResult, isPlus ? JavaTokenType.PLUS : JavaTokenType.MINUS, type.getCanonicalText())
+            operand, unboxedExpectedType != null? new BoxingEvaluator(rightEval) : rightEval
           );
         }
         catch (IncorrectOperationException e) {
@@ -639,7 +687,15 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
         }
       }
       else {
-        myResult = new UnaryExpressionEvaluator(opType, type.getCanonicalText(), operand, expression.getOperationSign().getText());
+        PsiType expected = expressionType;
+        final PsiPrimitiveType unboxedExpectedType = PsiPrimitiveType.getUnboxedType(expected);
+        if (unboxedExpectedType != null) {
+          expected = unboxedExpectedType;
+        }
+        final UnaryExpressionEvaluator unaryEvaluator =
+          new UnaryExpressionEvaluator(opType, expected.getCanonicalText(), new UnBoxingEvaluator(operand),
+                                       expression.getOperationSign().getText());
+        myResult = unboxedExpectedType != null? new BoxingEvaluator(unaryEvaluator) : unaryEvaluator;
       }
     }
 
@@ -768,11 +824,42 @@ public class EvaluatorBuilderImpl implements EvaluatorBuilder {
       myResult = new ArrayAccessEvaluator(arrayEvaluator, indexEvaluator);
     }
 
+    @SuppressWarnings({"ConstantConditions"})
     @Override
     public void visitTypeCastExpression(PsiTypeCastExpression expression) {
-      expression.getOperand().accept(this);
-      PsiType castType = expression.getCastType().getType();
-      myResult = new TypeCastEvaluator(myResult, castType.getCanonicalText(), castType instanceof PsiPrimitiveType);
+      final PsiExpression operandExpr = expression.getOperand();
+      operandExpr.accept(this);
+      Evaluator operandEvaluator = myResult;
+      final PsiType castType = expression.getCastType().getType();
+      final PsiType operandType = operandExpr.getType();
+
+      if (!TypeConversionUtil.areTypesConvertible(operandType, castType)) {
+        throw new EvaluateRuntimeException(
+          new EvaluateException(JavaErrorMessages.message("inconvertible.type.cast", HighlightUtil.formatType(operandType), HighlightUtil.formatType(castType)))
+        );
+      }
+
+      final boolean shouldPerformBoxingConversion = TypeConversionUtil.boxingConversionApplicable(castType, operandType);
+      final boolean castingToPrimitive = castType instanceof PsiPrimitiveType;
+      if (shouldPerformBoxingConversion && castingToPrimitive) {
+        operandEvaluator = new UnBoxingEvaluator(operandEvaluator);
+      }
+
+      final boolean performCastToWrapperClass = shouldPerformBoxingConversion && !castingToPrimitive;
+
+      String castTypeName = castType.getCanonicalText();
+      if (performCastToWrapperClass) {
+        final PsiPrimitiveType unboxedType = PsiPrimitiveType.getUnboxedType(castType);
+        if (unboxedType != null) {
+          castTypeName = unboxedType.getCanonicalText();
+        }
+      }
+
+      myResult = new TypeCastEvaluator(operandEvaluator, castTypeName, castingToPrimitive);
+      
+      if (performCastToWrapperClass) {
+        myResult = new BoxingEvaluator(myResult);
+      }
     }
 
     @Override
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IdentityEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/IdentityEvaluator.java
new file mode 100644 (file)
index 0000000..4ff1a85
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.sun.jdi.Value;
+
+/**
+* @author Eugene Zhuravlev
+*         Date: Feb 9, 2010
+*/
+public class IdentityEvaluator implements Evaluator {
+  private final Value myValue;
+
+  public IdentityEvaluator(Value value) {
+    myValue = value;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    return myValue;
+  }
+
+  public Modifier getModifier() {
+    return null;
+  }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnBoxingEvaluator.java b/java/debugger/impl/src/com/intellij/debugger/engine/evaluation/expression/UnBoxingEvaluator.java
new file mode 100644 (file)
index 0000000..faa9637
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2000-2010 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.intellij.debugger.engine.evaluation.expression;
+
+import com.intellij.debugger.engine.DebugProcessImpl;
+import com.intellij.debugger.engine.evaluation.EvaluateException;
+import com.intellij.debugger.engine.evaluation.EvaluationContextImpl;
+import com.intellij.openapi.util.Pair;
+import com.intellij.util.containers.HashMap;
+import com.sun.jdi.ClassType;
+import com.sun.jdi.Method;
+import com.sun.jdi.ObjectReference;
+import com.sun.jdi.Value;
+import org.jetbrains.annotations.Nullable;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * @author Eugene Zhuravlev
+ *         Date: Feb 8, 2010
+ */
+public class UnBoxingEvaluator implements Evaluator{
+  private final Evaluator myOperand;
+  private static final Map<String, Pair<String, String>> TYPES_TO_CONVERSION_METHOD_MAP = new HashMap<String, Pair<String, String>>();
+  static {
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Boolean", new Pair<String, String>("booleanValue", "()Z"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Byte", new Pair<String, String>("byteValue", "()B"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Character", new Pair<String, String>("charValue", "()C"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Short", new Pair<String, String>("shortValue", "()S"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Integer", new Pair<String, String>("intValue", "()I"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Long", new Pair<String, String>("longValue", "()J"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Float", new Pair<String, String>("floatValue", "()F"));
+    TYPES_TO_CONVERSION_METHOD_MAP.put("java.lang.Double", new Pair<String, String>("doubleValue", "()D"));
+  }
+
+  public static boolean isTypeUnboxable(String typeName) {
+    return TYPES_TO_CONVERSION_METHOD_MAP.containsKey(typeName);
+  }
+
+  public UnBoxingEvaluator(Evaluator operand) {
+    myOperand = operand;
+  }
+
+  public Object evaluate(EvaluationContextImpl context) throws EvaluateException {
+    final Value result = (Value)myOperand.evaluate(context);
+    if (result instanceof ObjectReference) {
+      final String valueTypeName = result.type().name();
+      final Pair<String, String> pair = TYPES_TO_CONVERSION_METHOD_MAP.get(valueTypeName);
+      if (pair != null) {
+        return convertToPrimitive(context, (ObjectReference)result, pair.getFirst(), pair.getSecond());
+      }
+    }
+    return result;
+  }
+                                          
+  @Nullable
+  public Modifier getModifier() {
+    return null;
+  }
+
+  private static Value convertToPrimitive(EvaluationContextImpl context, ObjectReference value, final String conversionMethodName,
+                                          String conversionMethodSignature) throws EvaluateException {
+    final DebugProcessImpl process = context.getDebugProcess();
+    final ClassType wrapperClass = (ClassType)value.referenceType();
+    final List<Method> methods = wrapperClass.methodsByName(conversionMethodName, conversionMethodSignature);
+    if (methods.size() == 0) { 
+      throw new EvaluateException("Cannot convert to primitive value of type " + value.type() + ": Unable to find method " +
+                                  conversionMethodName + conversionMethodSignature);
+    }
+
+    final Method method = methods.get(0);
+
+    return process.invokeMethod(context, value, method, new ArrayList());
+  }
+}
\ No newline at end of file