blob: 9f13087e93be912e535e1c012e1403da378c03ba [file] [log] [blame]
package org.eclipse.jdt.internal.debug.core.model;
/*
* (c) Copyright IBM Corp. 2000, 2001.
* All Rights Reserved.
*/
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 org.eclipse.jdt.debug.core.IJavaVariable;
import com.sun.jdi.ClassType;
import com.sun.jdi.Field;
import com.sun.jdi.InterfaceType;
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();
}
List methods = refType.methodsByName(selector, signature);
if (methods.isEmpty()) {
requestFailed(MessageFormat.format(JDIDebugModelMessages.getString("JDIObjectValue.Receiver_does_not_implement_selector"), new String[] {selector, signature}), null); //$NON-NLS-1$
} else {
method = (Method)methods.get(0);
}
} 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);
return JDIValue.createValue((JDIDebugTarget)getDebugTarget(), result);
}
/**
* 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$")) {
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, enclosingThis= null, 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$")) {
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;
}
}