| /******************************************************************************* |
| * Copyright (c) 2001, 2005 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 |
| *******************************************************************************/ |
| /* |
| |
| |
| */ |
| package org.eclipse.jem.internal.adapters.jdom; |
| |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.eclipse.emf.common.notify.Notifier; |
| import org.eclipse.emf.ecore.EObject; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.emf.ecore.xmi.XMIResource; |
| import org.eclipse.jdt.core.*; |
| |
| import org.eclipse.jem.internal.java.adapters.IJavaMethodAdapter; |
| import org.eclipse.jem.internal.java.adapters.ReadAdaptor; |
| import org.eclipse.jem.internal.java.adapters.nls.ResourceHandler; |
| import org.eclipse.jem.java.*; |
| import org.eclipse.jem.java.internal.impl.MethodImpl; |
| import org.eclipse.jem.util.TimerTests; |
| import org.eclipse.jem.internal.plugin.JavaPlugin; |
| |
| /** |
| * Java Method Reflection Adapter for JDOM (i.e. JDT model) |
| * Creation date: (6/6/2000 4:42:50 PM) |
| * @author: Administrator |
| */ |
| public class JavaMethodJDOMAdaptor extends JDOMAdaptor implements IJavaMethodAdapter { |
| |
| /* |
| * Step ids used for TimerTests of performance testing. |
| */ |
| public static final String REFLECT_METHOD = "Reflect JDOM Method"; //$NON-NLS-1$ |
| |
| protected IMethod sourceMethod = null; |
| |
| protected IType parentType = null; |
| |
| public JavaMethodJDOMAdaptor(Notifier target, IJavaProject workingProject) { |
| super(target, workingProject); |
| } |
| |
| |
| protected boolean flushReflectedValues(boolean clearCachedModelObject) { |
| if (clearCachedModelObject) |
| clearSource(); |
| MethodImpl method = (MethodImpl) getTarget(); |
| method.setIsGenerated(false); |
| method.setFinal(false); |
| method.setNative(false); |
| method.setStatic(false); |
| method.setSynchronized(false); |
| method.setConstructor(false); |
| method.setAbstract(false); |
| method.setJavaVisibility(JavaVisibilityKind.PUBLIC_LITERAL); |
| method.setEType(null); |
| method.getParametersGen().clear(); |
| method.getJavaExceptionsGen().clear(); |
| parentType = null; |
| return true; |
| } |
| |
| protected void postFlushReflectedValuesIfNecessary(boolean isExisting) { |
| ((MethodImpl) getTarget()).setReflected(false); |
| super.postFlushReflectedValuesIfNecessary(isExisting); |
| } |
| /** |
| * addExceptions - reflect our exception list |
| */ |
| protected void addExceptions() { |
| try { |
| IMethod sourceMethod = getSourceMethod(); |
| String[] exceptionNames = sourceMethod.getExceptionTypes(); |
| List exceptions = ((MethodImpl) getTarget()).getJavaExceptionsGen(); |
| for (int i = 0; i < exceptionNames.length; i++) { |
| exceptions.add(createJavaClassRef(typeNameFromSignature(exceptionNames[i]))); |
| } |
| } catch (JavaModelException npe) { |
| // name stays null and we carry on |
| } |
| } |
| |
| |
| protected String[] getParameterNames() { |
| String[] parmNames = new String[0], parmTypeNames = getSourceMethod().getParameterTypes(); |
| try { |
| parmNames = getSourceMethod().getParameterNames(); |
| } catch (JavaModelException npe) { |
| // name stays null and we carry on |
| } |
| // Temp hack to work around a JavaModel bug, above call on a Binary method may return null |
| if (parmNames == null || parmNames.length == 0) { |
| parmNames = new String[parmTypeNames.length]; |
| for (int i = 0; i < parmTypeNames.length; i++) { |
| parmNames[i] = "arg" + i;//$NON-NLS-1$ |
| } |
| } |
| return parmNames; |
| } |
| |
| /** |
| * addParameters - reflect our parms |
| */ |
| protected void addParameters() { |
| String[] parmTypeNames = getSourceMethod().getParameterTypes(); |
| MethodImpl javaMethodTarget = (MethodImpl) getTarget(); |
| List params = javaMethodTarget.getParametersGen(); |
| for (int i = 0; i < parmTypeNames.length; i++) { |
| params.add(createJavaParameter(javaMethodTarget, null, typeNameFromSignature(parmTypeNames[i]))); |
| } |
| } |
| |
| protected void clearSource() { |
| sourceMethod = null; |
| } |
| |
| protected JavaClass getContainingJavaClass() { |
| return ((Method) getTarget()).getContainingJavaClass(); |
| } |
| |
| /** |
| * getParentType - return the IType which corresponds to our parent JavaClass we're going to do this a lot, so cache it. |
| */ |
| protected IType getParentType() { |
| if (parentType == null) { |
| Method targetMethod = (Method) getTarget(); |
| if(targetMethod != null){ |
| JavaClass parentJavaClass = targetMethod.getContainingJavaClass(); |
| JavaClassJDOMAdaptor pa = (JavaClassJDOMAdaptor) EcoreUtil.getAdapter(parentJavaClass.eAdapters(), ReadAdaptor.TYPE_KEY); |
| if (pa != null) |
| parentType = pa.getSourceType(); |
| } |
| } |
| return parentType; |
| } |
| |
| /** |
| * getParmTypeSignatures - return an array of Strings (in Signature format) for our parameter types For reflection purposes, we can only rely on |
| * our UUID, since our parms may not yet be known. see org.eclipse.jdt.core.SourceMapper.convertTypeNamesToSigs() |
| */ |
| protected String[] getParmTypeSignatures() { |
| Method javaMethodTarget = (Method) getTarget(); |
| String[] typeNames = getTypeNamesFromMethodID(((XMIResource) javaMethodTarget.eResource()).getID(javaMethodTarget)); |
| if (typeNames == null) |
| return emptyStringArray; |
| int n = typeNames.length; |
| if (n == 0) |
| return emptyStringArray; |
| String[] typeSigs = new String[n]; |
| try { |
| for (int i = 0; i < n; ++i) { |
| typeSigs[i] = Signature.createTypeSignature(new String(typeNames[i]), getParentType().isBinary()); |
| } |
| } catch (IllegalArgumentException e) { |
| JavaPlugin.logError(e); |
| } |
| return typeSigs; |
| } |
| |
| public Object getReflectionSource() { |
| return getSourceMethod(); |
| } |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.java.adapters.JavaReflectionAdaptor#hasReflectionSource() |
| */ |
| public boolean hasCachedReflectionSource() { |
| return sourceMethod != null; |
| } |
| |
| /* |
| * Used by Java Class JDOM adapter to create and set with a source method/ |
| */ |
| public void primSetMethod(IMethod method) { |
| sourceMethod = method; |
| } |
| /** |
| * getsourceMethod - return the IMethod which describes our implementing method |
| */ |
| public IMethod getSourceMethod() { |
| if ((sourceMethod == null) || (!sourceMethod.exists())) { |
| try { |
| IType parent = this.getParentType(); |
| if (parent != null) { |
| String[] parmNames = this.getParmTypeSignatures(); |
| sourceMethod = JDOMSearchHelper.searchForMatchingMethod(parent, ((Method) getTarget()).getName(), parmNames); |
| } |
| } catch (JavaModelException e) { |
| //do nothing |
| } |
| } |
| return sourceMethod; |
| } |
| |
| protected IType getType() { |
| return getParentType(); |
| } |
| |
| protected Map getTypeResolutionCache() { |
| Method method = (Method) getTarget(); |
| if (method != null) { |
| JavaClass javaClass = method.getJavaClass(); |
| if (javaClass != null) { |
| JDOMAdaptor classAdaptor = (JDOMAdaptor) retrieveAdaptorFrom(javaClass); |
| if (classAdaptor != null) |
| return classAdaptor.getTypeResolutionCache(); |
| } |
| } |
| return null; |
| } |
| |
| /** |
| * getValueIn method comment. |
| */ |
| public Object getValueIn(EObject object, EObject attribute) { |
| // At this point, this adapter does not dynamically compute any values, |
| // all values are pushed back into the target on the initial call. |
| return super.getValueIn(object, attribute); |
| } |
| |
| /** |
| * reflectValues - template method, subclasses override to pump values into target. on entry: UUID, name, containing package (and qualified name), |
| * and document must be set. Method adaptor: - set modifiers - set name - set return type - add parameters - add exceptions |
| */ |
| public boolean reflectValues() { |
| super.reflectValues(); |
| try { |
| TimerTests.basicTest.startCumulativeStep(REFLECT_METHOD); |
| if (isResourceLoaded() && getSourceProject() != null && getSourceMethod() != null && sourceMethod.exists()) { |
| setModifiers(); |
| setNaming(); |
| setReturnType(); |
| addParameters(); |
| addExceptions(); |
| return true; |
| } |
| } finally { |
| TimerTests.basicTest.stopCumulativeStep(REFLECT_METHOD); |
| } |
| return false; |
| } |
| |
| /** |
| * Set the generated flag if @generated is found in the source. |
| */ |
| protected void setGeneratedFlag() { |
| Method methodTarget = (Method) getTarget(); |
| try { |
| String source = getSourceMethod().getSource(); |
| if (source != null) { |
| int index = source.indexOf(Method.GENERATED_COMMENT_TAG); |
| if (index > 0) |
| methodTarget.setIsGenerated(true); |
| } |
| } catch (JavaModelException npe) { |
| //System.out.println(ResourceHandler.getString("Error_Setting_GenFlag_ERROR_", new Object[] |
| // {((XMIResource)methodTarget.eResource()).getID(methodTarget), npe.getMessage()})); //$NON-NLS-1$ = "error setting the generated flag on |
| // {0}, exception: {1}" |
| } |
| } |
| |
| |
| /* (non-Javadoc) |
| * @see org.eclipse.jem.internal.java.adapters.IJavaMethodAdapter#reflectGeneratedIfNecessary() |
| */ |
| public boolean reflectGeneratedIfNecessary() { |
| if (reflectValuesIfNecessary()) { |
| setGeneratedFlag(); |
| return true; |
| } |
| return false; |
| } |
| |
| public boolean reflectParamNamesIfNecessary() { |
| if (reflectValuesIfNecessary()) { |
| String [] paramNames = getParameterNames(); |
| List param = ((MethodImpl)getTarget()).getParameters(); |
| for (int i = 0; i < paramNames.length; i++) { |
| ((JavaParameter)param.get(i)).setName(paramNames[i]); |
| } |
| return true; |
| } |
| return false; |
| } |
| /** |
| * setModifiers - set the attribute values related to modifiers here |
| */ |
| protected void setModifiers() { |
| Method methodTarget = (Method) getTarget(); |
| try { |
| methodTarget.setFinal(Flags.isFinal(getSourceMethod().getFlags())); |
| methodTarget.setNative(Flags.isNative(getSourceMethod().getFlags())); |
| methodTarget.setStatic(Flags.isStatic(getSourceMethod().getFlags())); |
| methodTarget.setSynchronized(Flags.isSynchronized(getSourceMethod().getFlags())); |
| methodTarget.setConstructor(getSourceMethod().isConstructor()); |
| |
| JavaClass javaClass = getContainingJavaClass(); |
| //Set abstract |
| if (javaClass.getKind().getValue() == TypeKind.INTERFACE) |
| methodTarget.setAbstract(true); |
| else |
| methodTarget.setAbstract(Flags.isAbstract(getSourceMethod().getFlags())); |
| // Set visibility |
| if (javaClass.getKind().getValue() == TypeKind.INTERFACE || Flags.isPublic(getSourceMethod().getFlags())) |
| methodTarget.setJavaVisibility(JavaVisibilityKind.PUBLIC_LITERAL); |
| else if (Flags.isPrivate(getSourceMethod().getFlags())) |
| methodTarget.setJavaVisibility(JavaVisibilityKind.PRIVATE_LITERAL); |
| else if (Flags.isProtected(getSourceMethod().getFlags())) |
| methodTarget.setJavaVisibility(JavaVisibilityKind.PROTECTED_LITERAL); |
| else |
| //Visibility must be package |
| methodTarget.setJavaVisibility(JavaVisibilityKind.PACKAGE_LITERAL); |
| } catch (JavaModelException npe) { |
| System.out |
| .println(ResourceHandler |
| .getString( |
| "Error_Introspecting_Flags_ERROR_", (new Object[] { ((XMIResource) methodTarget.eResource()).getID(methodTarget), npe.getMessage()}))); //$NON-NLS-1$ = "error introspecting flags on {0}, exception: {1}" |
| } |
| } |
| |
| /** |
| * setNaming - set the naming values here - qualified name must be set first, that is the path to the real Java class - ID - name-based UUID |
| */ |
| protected void setNaming() { |
| // |
| // naming is currently a no-op since the name and UUID must be set prior to reflection |
| // ...and ID is redundant with UUID. |
| // javaFieldTarget.setID(parent.getQualifiedName() + "_" + javaFieldTarget.getName()); |
| } |
| |
| /** |
| * setType - set our return type here |
| */ |
| protected void setReturnType() { |
| String typeName = null; |
| try { |
| typeName = typeNameFromSignature(getSourceMethod().getReturnType()); |
| } catch (JavaModelException npe) { |
| // name stays null and we carry on |
| } |
| if (typeName != null) { |
| Method javaMethodTarget = (Method) getTarget(); |
| javaMethodTarget.setEType(createJavaClassRef(typeName)); |
| } |
| } |
| |
| /** |
| * Insert the method's description here. Creation date: (10/3/2001 10:08:34 AM) |
| * |
| * @param newSourceMethod |
| * org.eclipse.jdt.core.IMethod |
| */ |
| public void setSourceMethod(org.eclipse.jdt.core.IMethod newSourceMethod) { |
| sourceMethod = newSourceMethod; |
| } |
| |
| /* |
| * Override to tolerate JDK 5 variable types. |
| * @see org.eclipse.jem.internal.adapters.jdom.JDOMAdaptor#typeNameFromSignature(java.lang.String) |
| */ |
| protected String typeNameFromSignature(String typeSignature) { |
| String erasure = null; |
| try { |
| erasure = Signature.getTypeErasure(typeSignature); |
| } catch (IllegalArgumentException e) { |
| //The signature is not the correct format for a variable. |
| } |
| if (erasure != null) { |
| String variableName = null; |
| String resolvedVariable = null; |
| |
| int arrayCount = Signature.getArrayCount(erasure); |
| if (arrayCount > 0) { |
| //We have an array. Check if the element type is a variable. |
| String elementTypeName = Signature.getElementType(erasure); |
| variableName = Signature.toString(elementTypeName); |
| resolvedVariable = resolveVariableName(erasure, variableName); |
| if (resolvedVariable != null) { |
| //Add array info. |
| StringBuffer b = new StringBuffer(resolvedVariable); |
| for (int i = 0; i < arrayCount; i++) { |
| b.append("[]"); //$NON-NLS-1$ |
| } |
| resolvedVariable = b.toString(); |
| } |
| } else { |
| variableName = Signature.toString(erasure); |
| //Need to resolve the variable. |
| resolvedVariable = resolveVariableName(erasure, variableName); |
| } |
| if (resolvedVariable == null) { |
| return super.typeNameFromSignature(erasure); |
| } else { |
| return resolvedVariable; |
| } |
| } |
| return super.typeNameFromSignature(typeSignature); |
| } |
| |
| |
| private String resolveVariableName(String erasure, String variableName) { |
| IMethod method = getSourceMethod(); |
| ITypeParameter[] typeParameters = null; |
| try { |
| typeParameters = method.getTypeParameters(); |
| } catch (JavaModelException e1) { |
| //Failed to retrieve type parameters for any number of reasons. |
| } |
| ITypeParameter typeParam = null; |
| if (typeParameters != null && typeParameters.length > 0) { |
| for (int i = 0; i < typeParameters.length; i++) { |
| if (typeParameters[i].exists() && variableName.equals(typeParameters[i].getElementName())) { |
| typeParam = typeParameters[i]; |
| break; |
| } |
| } |
| if (typeParam != null) { |
| String[] bounds = null; |
| try { |
| bounds = typeParam.getBounds(); |
| } catch (JavaModelException e) {} |
| if (bounds != null && bounds.length > 0) { |
| return JDOMSearchHelper.getResolvedTypeName(bounds[0], getType(), getTypeResolutionCache()); |
| } else { |
| return "java.lang.Object"; |
| } |
| } |
| } |
| |
| IJavaElement parent = method.getParent(); |
| if (parent instanceof IType) |
| { |
| try { |
| typeParameters = ((IType)parent).getTypeParameters(); |
| } catch (JavaModelException e1) { |
| //Failed to retrieve type parameters for any number of reasons. |
| } |
| } |
| if (typeParameters != null && typeParameters.length > 0) { |
| for (int i = 0; i < typeParameters.length; i++) { |
| if (typeParameters[i].exists() && variableName.equals(typeParameters[i].getElementName())) { |
| typeParam = typeParameters[i]; |
| break; |
| } |
| } |
| if (typeParam != null) { |
| String[] bounds = null; |
| try { |
| bounds = typeParam.getBounds(); |
| } catch (JavaModelException e) {} |
| if (bounds != null && bounds.length > 0) { |
| return JDOMSearchHelper.getResolvedTypeName(bounds[0], getType(), getTypeResolutionCache()); |
| } else { |
| return "java.lang.Object"; |
| } |
| } |
| } |
| return null; |
| } |
| } |