/******************************************************************************* * Copyright (c) 2000, 2015 IBM Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation * Jesper Steen Møller <jesper@selskabet.org> - Bug 430839 *******************************************************************************/ package org.eclipse.jdt.internal.debug.core.model; 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.core.Signature; import org.eclipse.jdt.debug.core.IJavaClassObject; import org.eclipse.jdt.debug.core.IJavaFieldVariable; import org.eclipse.jdt.debug.core.IJavaObject; import org.eclipse.jdt.debug.core.IJavaReferenceType; import org.eclipse.jdt.debug.core.IJavaValue; import com.ibm.icu.text.MessageFormat; import com.sun.jdi.AbsentInformationException; import com.sun.jdi.ArrayType; import com.sun.jdi.ClassLoaderReference; import com.sun.jdi.ClassNotLoadedException; import com.sun.jdi.Field; import com.sun.jdi.ObjectReference; import com.sun.jdi.ReferenceType; import com.sun.jdi.Type; import com.sun.jdi.Value; import com.sun.jdi.VirtualMachine; /** * References a class, interface, or array type. */ public abstract class JDIReferenceType extends JDIType implements IJavaReferenceType { // field names declared in this type private String[] fDeclaredFields = null; // field names declared in this type, super types, implemented interfaces // and super-interfaces private String[] fAllFields = null; /** * Constructs a new reference type in the given target. * * @param target * associated VM * @param type * reference type */ public JDIReferenceType(JDIDebugTarget target, Type type) { super(target, type); } /* * (non-Javadoc) * * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getAvailableStrata() */ @Override public String[] getAvailableStrata() { List<String> strata = getReferenceType().availableStrata(); return strata.toArray(new String[strata.size()]); } /** * Returns the underlying reference type. * * @return the underlying reference type */ protected ReferenceType getReferenceType() { return (ReferenceType) getUnderlyingType(); } /* * (non-Javadoc) * * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getDefaultStratum() */ @Override public String getDefaultStratum() throws DebugException { try { return getReferenceType().defaultStratum(); } catch (RuntimeException e) { targetRequestFailed(JDIDebugModelMessages.JDIReferenceType_1, e); } // execution will not reach here return null; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.debug.core.IJavaReferenceType#getField(java.lang.String) */ @Override public IJavaFieldVariable getField(String name) throws DebugException { try { ReferenceType type = (ReferenceType) getUnderlyingType(); Field field = type.fieldByName(name); if (field != null && field.isStatic()) { return new JDIFieldVariable(getJavaDebugTarget(), field, type); } } catch (RuntimeException e) { targetRequestFailed( MessageFormat.format( JDIDebugModelMessages.JDIClassType_exception_while_retrieving_field, e.toString(), name), e); } // it is possible to return null return null; } /* * (non-Javadoc) * * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getClassObject() */ @Override public IJavaClassObject getClassObject() throws DebugException { try { ReferenceType type = (ReferenceType) getUnderlyingType(); return (IJavaClassObject) JDIValue.createValue( getJavaDebugTarget(), type.classObject()); } catch (RuntimeException e) { targetRequestFailed( MessageFormat.format( JDIDebugModelMessages.JDIClassType_exception_while_retrieving_class_object, e.toString()), e); } // execution will not fall through to here, // as #requestFailed will throw an exception return null; } /* * (non-Javadoc) * * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getAllFieldNames() */ @Override public String[] getAllFieldNames() throws DebugException { if (fAllFields == null) { try { List<Field> fields = ((ReferenceType) getUnderlyingType()).allFields(); fAllFields = new String[fields.size()]; Iterator<Field> iterator = fields.iterator(); int i = 0; while (iterator.hasNext()) { Field field = iterator.next(); fAllFields[i] = field.name(); i++; } } catch (RuntimeException e) { targetRequestFailed(JDIDebugModelMessages.JDIReferenceType_2, e); } } return fAllFields; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.debug.core.IJavaReferenceType#getDeclaredFieldNames() */ @Override public String[] getDeclaredFieldNames() throws DebugException { if (fDeclaredFields == null) { try { List<Field> fields = ((ReferenceType) getUnderlyingType()).fields(); fDeclaredFields = new String[fields.size()]; Iterator<Field> iterator = fields.iterator(); int i = 0; while (iterator.hasNext()) { Field field = iterator.next(); fDeclaredFields[i] = field.name(); i++; } } catch (RuntimeException e) { targetRequestFailed(JDIDebugModelMessages.JDIReferenceType_3, e); } } return fDeclaredFields; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.debug.core.IJavaReferenceType#getSourcePaths(java.lang * .String) */ @Override public String[] getSourcePaths(String stratum) throws DebugException { try { List<String> sourcePaths = getReferenceType().sourcePaths(stratum); return sourcePaths .toArray(new String[sourcePaths.size()]); } catch (AbsentInformationException e) { } catch (RuntimeException e) { requestFailed(JDIDebugModelMessages.JDIReferenceType_4, e, DebugException.TARGET_REQUEST_FAILED); } return null; } /* * (non-Javadoc) * * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getSourceName() */ @Override public String getSourceName() throws DebugException { try { return getReferenceType().sourceName(); } catch (AbsentInformationException e) { } catch (RuntimeException e) { requestFailed(JDIDebugModelMessages.JDIReferenceType_4, e, DebugException.TARGET_REQUEST_FAILED); } return null; } /* * (non-Javadoc) * * @see * org.eclipse.jdt.debug.core.IJavaReferenceType#getSourceNames(java.lang * .String) */ @Override public String[] getSourceNames(String stratum) throws DebugException { try { List<String> sourceNames = getReferenceType().sourceNames(stratum); return sourceNames .toArray(new String[sourceNames.size()]); } catch (AbsentInformationException e) { } catch (RuntimeException e) { requestFailed(JDIDebugModelMessages.JDIReferenceType_4, e, DebugException.TARGET_REQUEST_FAILED); } return null; } /* * (non-Javadoc) * * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getClassLoaderObject() */ @Override public IJavaObject getClassLoaderObject() throws DebugException { try { ReferenceType type = (ReferenceType) getUnderlyingType(); ClassLoaderReference classLoader = type.classLoader(); if (classLoader != null) { return (IJavaObject) JDIValue.createValue(getJavaDebugTarget(), classLoader); } } catch (RuntimeException e) { targetRequestFailed(MessageFormat.format( JDIDebugModelMessages.JDIReferenceType_0, e.toString()), e); } return null; } static public String getGenericName(ReferenceType type) throws DebugException { if (type instanceof ArrayType) { try { Type componentType; componentType = ((ArrayType) type).componentType(); if (componentType instanceof ReferenceType) { return getGenericName((ReferenceType) componentType) + "[]"; //$NON-NLS-1$ } return type.name(); } catch (ClassNotLoadedException e) { // we cannot create the generic name using the component type, // just try to create one with the information } } String signature = type.signature(); StringBuffer res = new StringBuffer(getTypeName(signature)); String genericSignature = type.genericSignature(); if (genericSignature != null) { String[] typeParameters = Signature .getTypeParameters(genericSignature); if (typeParameters.length > 0) { res.append('<').append( Signature.getTypeVariable(typeParameters[0])); for (int i = 1; i < typeParameters.length; i++) { res.append(',').append( Signature.getTypeVariable(typeParameters[i])); } res.append('>'); } } return res.toString(); } /** * Return the name from the given signature. Keep the '$' characters. * * @param genericTypeSignature * the signature to derive the type name from * @return the type name */ public static String getTypeName(String genericTypeSignature) { int arrayDimension = 0; while (genericTypeSignature.charAt(arrayDimension) == '[') { arrayDimension++; } int parameterStart = genericTypeSignature.indexOf('<'); StringBuffer name = new StringBuffer(); if (parameterStart < 0) { name.append(genericTypeSignature.substring(arrayDimension + 1, genericTypeSignature.length() - 1).replace('/', '.')); } else { if (parameterStart != 0) { name.append(genericTypeSignature.substring(arrayDimension + 1, parameterStart).replace('/', '.')); } try { String sig = Signature.toString(genericTypeSignature) .substring( Math.max(parameterStart - 1, 0) - arrayDimension); name.append(sig.replace('/', '.')); } catch (IllegalArgumentException iae) { // do nothing name.append(genericTypeSignature); } } for (int i = 0; i < arrayDimension; i++) { name.append("[]"); //$NON-NLS-1$ } return name.toString(); } /* * (non-Javadoc) * * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getGenericSignature() */ @Override public String getGenericSignature() throws DebugException { return getReferenceType().genericSignature(); } /* * (non-Javadoc) * * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getInstances(long) */ @Override public IJavaObject[] getInstances(long max) throws DebugException { try { List<ObjectReference> list = getReferenceType().instances(max); IJavaObject[] instances = new IJavaObject[list.size()]; for (int i = 0; i < instances.length; i++) { instances[i] = (IJavaObject) JDIValue.createValue( getJavaDebugTarget(), list.get(i)); } return instances; } catch (RuntimeException e) { targetRequestFailed(JDIDebugModelMessages.JDIReferenceType_5, e); } return null; } /* * (non-Javadoc) * * @see org.eclipse.jdt.debug.core.IJavaReferenceType#getInstanceCount() */ @Override public long getInstanceCount() throws DebugException { JDIDebugTarget target = getJavaDebugTarget(); if (target.supportsInstanceRetrieval()) { Type type = getUnderlyingType(); if(type instanceof ReferenceType) { ArrayList<ReferenceType> list = new ArrayList<>(2); list.add((ReferenceType) type); VirtualMachine vm = getVM(); try { long[] counts = vm.instanceCounts(list); return counts[0]; } catch (RuntimeException e) { targetRequestFailed(JDIDebugModelMessages.JDIReferenceType_5, e); } } } return -1; } /** * Utility method to convert argument array to an argument list. * * @param args * array of arguments, as <code>IJavaValue</code>s, possibly * <code>null</code> or empty * @return a list of underlying <code>Value</code>s */ protected List<Value> convertArguments(IJavaValue[] args) { List<Value> arguments = null; if (args == null) { arguments = Collections.EMPTY_LIST; } else { arguments = new ArrayList<>(args.length); for (IJavaValue arg : args) { arguments.add(((JDIValue) arg).getUnderlyingValue()); } } return arguments; } }