Copyright (c) 2017, 2018 GK Software AG, and others. This program and the accompanying materials are made available under the terms of the Eclipse Public License 2.0 which accompanies this distribution, and is available at https://www.eclipse.org/legal/epl-2.0/ SPDX-License-Identifier: EPL-2.0 Contributors: Stephan Herrmann - initial API and implementation
/******************************************************************************* * Copyright (c) 2017, 2018 GK Software AG, and others. * * This program and the accompanying materials * are made available under the terms of the Eclipse Public License 2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/legal/epl-2.0/ * * SPDX-License-Identifier: EPL-2.0 * * Contributors: * Stephan Herrmann - initial API and implementation *******************************************************************************/
package org.eclipse.jdt.internal.core; import java.io.IOException; import java.util.Map; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.jdt.core.*; import org.eclipse.jdt.internal.compiler.classfmt.ClassFileReader; import org.eclipse.jdt.internal.compiler.classfmt.ClassFormatException; import org.eclipse.jdt.internal.compiler.env.IBinaryModule; import org.eclipse.jdt.internal.compiler.env.IDependent; import org.eclipse.jdt.internal.compiler.env.IModule; import org.eclipse.jdt.internal.compiler.lookup.TypeConstants; import org.eclipse.jdt.internal.core.nd.java.model.BinaryModuleDescriptor; import org.eclipse.jdt.internal.core.nd.java.model.BinaryModuleFactory; import org.eclipse.jdt.internal.core.util.MementoTokenizer; import org.eclipse.jdt.internal.core.util.Util;
A handle to a modular class file.
/** * A handle to a modular class file. */
public class ModularClassFile extends AbstractClassFile implements IModularClassFile { private BinaryModule binaryModule; protected ModularClassFile(PackageFragment parent) { super(parent, TypeConstants.MODULE_INFO_NAME_STRING); }
Creates the single child element for this class file adding the resulting new handle (of type IBinaryModule) and info object to the newElements table. Returns true if successful, or false if an error is encountered parsing the class file.
See Also:
/** * Creates the single child element for this class file adding the resulting * new handle (of type {@link IBinaryModule}) and info object to the newElements table. * Returns true if successful, or false if an error is encountered parsing the class file. * * @see Openable * @see Signature */
@Override protected boolean buildStructure(OpenableElementInfo info, IProgressMonitor pm, Map newElements, IResource underlyingResource) throws JavaModelException { IBinaryModule moduleInfo = getBinaryModuleInfo(); if (moduleInfo == null) { // The structure of a class file is unknown if a class file format errors occurred //during the creation of the diet class file representative of this ClassFile. info.setChildren(JavaElement.NO_ELEMENTS); return false; } // Create & link a handle: BinaryModule module = new BinaryModule(this, moduleInfo); newElements.put(module, moduleInfo); info.setChildren(new IJavaElement[] {module}); this.binaryModule = module; if (info instanceof ClassFileInfo) { ((ClassFileInfo) info).setModule(module); } ((PackageFragmentRootInfo) getPackageFragmentRoot().getElementInfo()).setModule(module); return true; } @Override public void codeComplete(int offset, CompletionRequestor requestor, WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException { String source = getSource(); if (source != null) { BasicCompilationUnit cu = new BasicCompilationUnit( getSource().toCharArray(), null, TypeConstants.MODULE_INFO_FILE_NAME_STRING, getJavaProject()); // use project to retrieve corresponding .java IFile codeComplete(cu, cu, offset, requestor, owner, null/*extended context isn't computed*/, monitor); } } @Override public IJavaElement[] codeSelect(int offset, int length, WorkingCopyOwner owner) throws JavaModelException { IBuffer buffer = getBuffer(); char[] contents; if (buffer != null && (contents = buffer.getCharacters()) != null) { BasicCompilationUnit cu = new BasicCompilationUnit(contents, null, TypeConstants.MODULE_INFO_FILE_NAME_STRING, this); return super.codeSelect(cu, offset, length, owner); } else { // has no associated source return new IJavaElement[] {}; } } @Override public IType findPrimaryType() { return null; } @Override public boolean isClass() throws JavaModelException { return false; } @Override public boolean isInterface() throws JavaModelException { return false; } @Override public IType getType() { throw new UnsupportedOperationException("IClassFile#getType() cannot be used on an IModularClassFile"); //$NON-NLS-1$ }
Returns the IBinaryModule specific for this IClassFile, based on its underlying resource, or null if unable to create the diet class file. There are two cases to consider:
  • a class file corresponding to an IFile resource
  • a class file corresponding to a zip entry in a JAR
Throws:
  • JavaModelException – when the IFile resource or JAR is not available or when this class file is not present in the JAR
/** * Returns the <code>IBinaryModule</code> specific for this IClassFile, based * on its underlying resource, or <code>null</code> if unable to create * the diet class file. * There are two cases to consider:<ul> * <li>a class file corresponding to an IFile resource</li> * <li>a class file corresponding to a zip entry in a JAR</li> * </ul> * * @exception JavaModelException when the IFile resource or JAR is not available * or when this class file is not present in the JAR */
public IBinaryModule getBinaryModuleInfo() throws JavaModelException { try { IBinaryModule info = getJarBinaryModuleInfo(); if (info == null) { throw newNotPresentException(); } return info; } catch (ClassFormatException cfe) { //the structure remains unknown if (JavaCore.getPlugin().isDebugging()) { cfe.printStackTrace(System.err); } return null; } catch (IOException ioe) { throw new JavaModelException(ioe, IJavaModelStatusConstants.IO_EXCEPTION); } catch (CoreException e) { if (e instanceof JavaModelException) { throw (JavaModelException)e; } else { throw new JavaModelException(e); } } } private IBinaryModule getJarBinaryModuleInfo() throws CoreException, IOException, ClassFormatException { BinaryModuleDescriptor descriptor = BinaryModuleFactory.createDescriptor(this); if (descriptor == null) { return null; } IBinaryModule result = null; IPackageFragmentRoot root = getPackageFragmentRoot(); if (getPackageFragmentRoot() instanceof JarPackageFragmentRoot) { if (root instanceof JrtPackageFragmentRoot || this.name.equals(IModule.MODULE_INFO)) { PackageFragment pkg = (PackageFragment) getParent(); JarPackageFragmentRoot jarRoot = (JarPackageFragmentRoot) getPackageFragmentRoot(); String entryName = jarRoot.getClassFilePath(Util.concatWith(pkg.names, getElementName(), '/')); byte[] contents = getClassFileContent(jarRoot, entryName); if (contents != null) { String fileName = root.getHandleIdentifier() + IDependent.JAR_FILE_ENTRY_SEPARATOR + entryName; ClassFileReader classFileReader = new ClassFileReader(contents, fileName.toCharArray(), false); return classFileReader.getModuleDeclaration(); } } else { result = BinaryModuleFactory.readModule(descriptor, null); } } else { result = BinaryModuleFactory.readModule(descriptor, null); } return result; }
See Also:
  • ITypeRoot
/** * @see ITypeRoot */
@Override public IJavaElement getElementAt(int position) throws JavaModelException { IJavaElement parentElement = getParent(); while (parentElement.getElementType() != IJavaElement.PACKAGE_FRAGMENT_ROOT) { parentElement = parentElement.getParent(); } PackageFragmentRoot root = (PackageFragmentRoot) parentElement; SourceMapper mapper = root.getSourceMapper(); if (mapper == null) { return null; } else { // ensure this class file's buffer is open so that source ranges are computed getBuffer(); IModuleDescription module = getModule(); return findElement(module, position, mapper); } } @Override public IJavaElement getHandleFromMemento(String token, MementoTokenizer memento, WorkingCopyOwner owner) { switch (token.charAt(0)) { case JEM_MODULE: if (!memento.hasMoreTokens()) return this; String modName = memento.nextToken(); JavaElement mod = new BinaryModule(this, modName); return mod.getHandleFromMemento(memento, owner); } return null; }
See Also:
  • getHandleMemento.getHandleMemento()
/** * @see JavaElement#getHandleMemento() */
@Override protected char getHandleMementoDelimiter() { return JavaElement.JEM_MODULAR_CLASSFILE; } @Override protected void escapeMementoName(StringBuffer buffer, String mementoName) { // nop, name is irrelevant } @Override public ICompilationUnit getWorkingCopy(WorkingCopyOwner owner, IProgressMonitor monitor) throws JavaModelException { CompilationUnit workingCopy = new ClassFileWorkingCopy(this, owner == null ? DefaultWorkingCopyOwner.PRIMARY : owner); JavaModelManager manager = JavaModelManager.getJavaModelManager(); JavaModelManager.PerWorkingCopyInfo perWorkingCopyInfo = manager.getPerWorkingCopyInfo(workingCopy, false/*don't create*/, true/*record usage*/, null/*not used since don't create*/); if (perWorkingCopyInfo != null) { return perWorkingCopyInfo.getWorkingCopy(); // return existing handle instead of the one created above } BecomeWorkingCopyOperation op = new BecomeWorkingCopyOperation(workingCopy, null); op.runOperation(monitor); return workingCopy; }
Opens and returns buffer on the source code associated with this class file. Maps the source code to the children elements of this class file. If no source code is associated with this class file, null is returned.
See Also:
  • Openable
/** * Opens and returns buffer on the source code associated with this class file. * Maps the source code to the children elements of this class file. * If no source code is associated with this class file, * <code>null</code> is returned. * * @see Openable */
@Override protected IBuffer openBuffer(IProgressMonitor pm, Object info) throws JavaModelException { SourceMapper mapper = getSourceMapper(); if (mapper != null) { return mapSource(mapper); } return null; }
Loads the buffer via SourceMapper, and maps it in SourceMapper
/** Loads the buffer via SourceMapper, and maps it in SourceMapper */
private IBuffer mapSource(SourceMapper mapper) throws JavaModelException { char[] contents = mapper.findSource(getModule()); if (contents != null) { // create buffer IBuffer buffer = BufferManager.createBuffer(this); if (buffer == null) return null; BufferManager bufManager = getBufferManager(); bufManager.addBuffer(buffer); // set the buffer source if (buffer.getCharacters() == null){ buffer.setContents(contents); } // listen to buffer changes buffer.addBufferChangedListener(this); // do the source mapping mapper.mapSource((NamedMember) getModule(), contents, null); return buffer; } else { // create buffer IBuffer buffer = BufferManager.createNullBuffer(this); if (buffer == null) return null; BufferManager bufManager = getBufferManager(); bufManager.addBuffer(buffer); // listen to buffer changes buffer.addBufferChangedListener(this); return buffer; } } @Override public IModuleDescription getModule() throws JavaModelException { if (this.binaryModule == null) { openWhenClosed(createElementInfo(), false, null); if (this.binaryModule == null) throw newNotPresentException(); } return this.binaryModule; } }