blob: 23efeaebf1a0d05319f335e66664ba464e213223 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2004 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Common Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/cpl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.jdt.internal.debug.core.model;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import org.eclipse.debug.core.DebugException;
import org.eclipse.jdt.debug.core.IJavaFieldVariable;
import org.eclipse.jdt.debug.core.IJavaObject;
import org.eclipse.jdt.debug.core.IJavaThread;
import org.eclipse.jdt.debug.core.IJavaValue;
import com.sun.jdi.ArrayType;
import com.sun.jdi.ClassType;
import com.sun.jdi.Field;
import com.sun.jdi.Method;
import com.sun.jdi.ObjectReference;
import com.sun.jdi.ReferenceType;
import com.sun.jdi.Value;
/**
* Implementation of a value referencing an object on the
* target VM.
*/
public class JDIObjectValue extends JDIValue implements IJavaObject {
/**
* Constructs a new target object on the given target with
* the specified object reference.
*/
public JDIObjectValue(JDIDebugTarget target, ObjectReference object) {
super(target, object);
}
/**
* @see IJavaObject#sendMessage(String, String, IJavaValue[], IJavaThread)
*/
public IJavaValue sendMessage(String selector, String signature, IJavaValue[] args, IJavaThread thread, boolean superSend) throws DebugException {
JDIThread javaThread = (JDIThread)thread;
List arguments = null;
if (args == null) {
arguments = Collections.EMPTY_LIST;
} else {
arguments= new ArrayList(args.length);
for (int i = 0; i < args.length; i++) {
arguments.add(((JDIValue)args[i]).getUnderlyingValue());
}
}
ObjectReference object = getUnderlyingObject();
Method method = null;
ReferenceType refType = getUnderlyingReferenceType();
try {
if (superSend) {
// begin lookup in superclass
refType = ((ClassType)refType).superclass();
}
method = concreteMethodByName(refType, selector, signature);
if (method == null) {
targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIObjectValue.11"), new String[] {selector, signature}), null); //$NON-NLS-1$
}
} catch (RuntimeException e) {
targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIObjectValue.exception_while_performing_method_lookup_for_selector"), new String[] {e.toString(), selector, signature}), e); //$NON-NLS-1$
}
Value result = javaThread.invokeMethod(null, object, method, arguments, superSend);
return JDIValue.createValue((JDIDebugTarget)getDebugTarget(), result);
}
/**
* @see IJavaObject#sendMessage(String, String, IJavaValue[], IJavaThread, String typeSignature)
*/
public IJavaValue sendMessage(String selector, String signature, IJavaValue[] args, IJavaThread thread, String typeSignature) throws DebugException {
JDIThread javaThread = (JDIThread)thread;
List arguments = null;
if (args == null) {
arguments = Collections.EMPTY_LIST;
} else {
arguments= new ArrayList(args.length);
for (int i = 0; i < args.length; i++) {
arguments.add(((JDIValue)args[i]).getUnderlyingValue());
}
}
ObjectReference object = getUnderlyingObject();
Method method = null;
ReferenceType refType = getUnderlyingReferenceType();
try {
while (typeSignature != null && !refType.signature().equals(typeSignature)) {
// lookup correct type through the hierarchy
refType = ((ClassType)refType).superclass();
if (refType == null) {
targetRequestFailed(JDIDebugModelMessages.getString("JDIObjectValueMethod_declaring_type_not_found_1"), null); //$NON-NLS-1$
}
}
method= concreteMethodByName(refType, selector, signature);
if (method == null) {
targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIObjectValue.11"), new String[] {selector, signature}), null); //$NON-NLS-1$
}
} catch (RuntimeException e) {
targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIObjectValue.exception_while_performing_method_lookup_for_selector"), new String[] {e.toString(), selector, signature}), e); //$NON-NLS-1$
}
Value result = javaThread.invokeMethod(null, object, method, arguments, true);
return JDIValue.createValue((JDIDebugTarget)getDebugTarget(), result);
}
private Method concreteMethodByName(ReferenceType refType, String selector, String signature) throws DebugException {
if (refType instanceof ClassType) {
return ((ClassType)refType).concreteMethodByName(selector, signature);
}
if (refType instanceof ArrayType) {
// the jdi spec specifies that all methods on methods return an empty list for array types.
// use a trick to get the right method from java.lang.Object
return ((ClassType)refType.classObject().referenceType()).superclass().concreteMethodByName(selector, signature);
}
targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIObjectValue.method_lookup_failed_for_selector___{0}___with_signature___{1}__1"), new String[] {selector, signature}), null); //$NON-NLS-1$
// it is not possible to return null
return null;
}
/**
* Returns this object's the underlying object reference
*
* @return underlying object reference
*/
public ObjectReference getUnderlyingObject() {
return (ObjectReference)getUnderlyingValue();
}
/**
* @see IJavaObject#getField(String, boolean)
*/
public IJavaFieldVariable getField(String name, boolean superField) throws DebugException {
ReferenceType ref = getUnderlyingReferenceType();
try {
if (superField) {
// begin lookup in superclass
ref = ((ClassType)ref).superclass();
}
Field field = ref.fieldByName(name);
if (field != null) {
return new JDIFieldVariable((JDIDebugTarget)getDebugTarget(), field, getUnderlyingObject());
} else {
Field enclosingThis= null;
Iterator fields= ref.fields().iterator();
while (fields.hasNext()) {
Field fieldTmp = (Field)fields.next();
if (fieldTmp.name().startsWith("this$")) { //$NON-NLS-1$
enclosingThis= fieldTmp;
break;
}
}
return ((JDIObjectValue)(new JDIFieldVariable((JDIDebugTarget)getDebugTarget(), enclosingThis, getUnderlyingObject())).getValue()).getField(name, false);
}
} catch (RuntimeException e) {
targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIObjectValue.exception_retrieving_field"), new String[]{e.toString()}), e); //$NON-NLS-1$
}
// it is possible to return null
return null;
}
/**
* @see IJavaObject#getField(String, String)
*/
public IJavaFieldVariable getField(String name, String declaringTypeSignature) throws DebugException {
ReferenceType ref= getUnderlyingReferenceType();
try {
Field field= null;
Field fieldTmp= null;
Iterator fields= ref.allFields().iterator();
while (fields.hasNext()) {
fieldTmp = (Field)fields.next();
if (name.equals(fieldTmp.name()) && declaringTypeSignature.equals(fieldTmp.declaringType().signature())) {
field= fieldTmp;
break;
}
}
if (field != null) {
return new JDIFieldVariable((JDIDebugTarget)getDebugTarget(), field, getUnderlyingObject());
}
} catch (RuntimeException e) {
targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIObjectValue.exception_retrieving_field"), new String[]{e.toString()}), e); //$NON-NLS-1$
}
// it is possible to return null
return null;
}
/**
* Returns a variable representing the field in this object
* with the given name, or <code>null</code> if there is no
* field with the given name, or the name is ambiguous.
*
* @param name field name
* @param superClassLevel the level of the desired field in the
* hierarchy. Level 0 returns the field from the current type, level 1 from the
* super type, etc.
* @return the variable representing the field, or <code>null</code>
* @exception DebugException if this method fails. Reasons include:
* <ul><li>Failure communicating with the VM. The DebugException's
* status code contains the underlying exception responsible for
* the failure.</li>
*/
public IJavaFieldVariable getField(String name, int superClassLevel) throws DebugException {
ReferenceType ref= getUnderlyingReferenceType();
try {
for (int i= 0 ; i < superClassLevel; i++) {
ref= ((ClassType)ref).superclass();
}
Field field = ref.fieldByName(name);
if (field != null) {
return new JDIFieldVariable((JDIDebugTarget)getDebugTarget(), field, getUnderlyingObject());
}
} catch (RuntimeException e) {
targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIObjectValue.exception_retrieving_field"), new String[]{e.toString()}), e); //$NON-NLS-1$
}
// it is possible to return null
return null;
}
/**
* Returns the underlying reference type for this object.
*
* @exception DebugException if this method fails. Reasons include:
* <ul><li>Failure communicating with the VM. The DebugException's
* status code contains the underlying exception responsible for
* the failure.</li>
*/
protected ReferenceType getUnderlyingReferenceType() throws DebugException {
try {
return getUnderlyingObject().referenceType();
} catch (RuntimeException e) {
targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIObjectValue.exception_retrieving_reference_type"), new String[]{e.toString()}), e); //$NON-NLS-1$
}
// execution will not reach this line, as an exception will
// be thrown.
return null;
}
/**
* Return the enclosing object of this object at the specified level.
* Level 0 returns the object, level 1 returns the enclosing object, etc.
*/
public IJavaObject getEnclosingObject(int enclosingLevel) throws DebugException {
JDIObjectValue res= this;
for (int i= 0; i < enclosingLevel; i ++) {
ReferenceType ref= res.getUnderlyingReferenceType();
try {
Field enclosingThis= null, fieldTmp= null;
Iterator fields= ref.fields().iterator();
while (fields.hasNext()) {
fieldTmp = (Field)fields.next();
if (fieldTmp.name().startsWith("this$")) { //$NON-NLS-1$
enclosingThis= fieldTmp;
}
}
if (enclosingThis != null) {
res= (JDIObjectValue)(new JDIFieldVariable((JDIDebugTarget)getDebugTarget(), enclosingThis, res.getUnderlyingObject())).getValue();
} else {
// it is possible to return null
return null;
}
} catch (RuntimeException e) {
targetRequestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIObjectValue.exception_retrieving_field"), new String[]{e.toString()}), e); //$NON-NLS-1$
}
}
return res;
}
}