Skip to main content


Eclipse Community Forums
Forum Search:

Search      Help    Register    Login    Home
Home » Language IDEs » Java Development Tools (JDT) » How to change the superclass extended by a type?
How to change the superclass extended by a type? [message #1385451] Fri, 06 June 2014 14:02 Go to next message
Joao L. is currently offline Joao L.Friend
Messages: 6
Registered: June 2014
Junior Member
Hey all,
I'm developing a plugin that, among other things, has to change imports and some superclasses (I have a text file indicating which types must be changed to which other types). I'm using an ASTVisitor and extending visit(TypeDeclaration). When I finally do typeDeclaration.setSuperclassType(newType); nothing seems to happen to the actual compilation unit. In debug, I can see that the TypeDeclaration parameter was updated, but in the end, the generated code remained unchanged. Any clues? I would also appreciate any tips in how to debug this further. It's hard to understand what's going on behind the scenes in ASTVisitor.

package plugin;

import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.SimpleType;
import org.eclipse.jdt.core.dom.TypeDeclaration;

public class SuperClassVisitor extends ASTVisitor{
	public SimpleType 	superClass;
	public String 	newSuperClass;
	private String 	oldSuperClass;
	
	
	public SuperClassVisitor(String newType, String oldType) {
		// HACK: use simple name instead of qualified name
		// This returns the simple name from the fully qualified name 
		String[] newTypes = newType.split("\\.");
		String[] oldTypes = oldType.split("\\.");
		this.newSuperClass = newTypes[newTypes.length-1]; 
		this.oldSuperClass = oldTypes[oldTypes.length-1];
	}

	public boolean visit(TypeDeclaration typeDeclaration) {
		
		superClass = (SimpleType) typeDeclaration.getSuperclassType();
		superClass.getNodeType();
		
		if (newSuperClass != null) {
			Name oldName = typeDeclaration.getAST().newName(oldSuperClass);
			SimpleType oldType = typeDeclaration.getAST().newSimpleType(oldName);
			
			Name newName = typeDeclaration.getAST().newName(newSuperClass);
			SimpleType newType = typeDeclaration.getAST().newSimpleType(newName);
			
			if (superClass != null && superClass.getName().getFullyQualifiedName().equals(oldType.getName().getFullyQualifiedName())) {
				typeDeclaration.setSuperclassType(newType);
			}
		}
		return false;
	}
}
Re: How to change the superclass extended by a type? [message #1385497 is a reply to message #1385451] Sat, 07 June 2014 12:54 Go to previous messageGo to next message
Stephan Herrmann is currently offline Stephan HerrmannFriend
Messages: 1853
Registered: July 2009
Senior Member
The AST is just a representation of the compilation unit, it doesn't automatically write back any changes.

Have you had a look at org.eclipse.jdt.core.dom.rewrite.ASTRewrite?
Please consult one of the JDT tutorials, the most recent copy being https://github.com/aupsy/org.eclipsecon2012.misc.tutorial/blob/master/Slides/How%20To%20Train%20the%20JDT%20Dragon%20combined.ppt?raw=true

See slide #46 ff.

HTH
Stephan
Re: How to change the superclass extended by a type? [message #1385498 is a reply to message #1385497] Sat, 07 June 2014 13:17 Go to previous messageGo to next message
Joao L. is currently offline Joao L.Friend
Messages: 6
Registered: June 2014
Junior Member
Thank you very much for pointing me to these tutorials. I'll try implementing this.
Re: How to change the superclass extended by a type? [message #1385925 is a reply to message #1385497] Thu, 12 June 2014 09:49 Go to previous messageGo to next message
Joao L. is currently offline Joao L.Friend
Messages: 6
Registered: June 2014
Junior Member
Thanks for pointing me in that direction. I'm now using ASTRewrite, but nothing happens, just like before. My code:

public static void setSuperclass(ICompilationUnit unit, 
  String newImportName, String oldImportName) {

  ASTParser parser = ASTParser.newParser(AST.JLS4);
  parser.setKind(ASTParser.K_COMPILATION_UNIT);
  parser.setSource(unit);
  parser.setResolveBindings(true);
  CompilationUnit astRoot = (CompilationUnit) parser.createAST(null);

  //create a ASTRewrite
  astRoot.recordModifications();
  ASTRewrite rewrite = ASTRewrite.create(astRoot.getAST());

  // Visit the node and perform the changes needed
  SuperClassVisitor visitor = new SuperClassVisitor(newImportName, oldImportName);
  astRoot.accept(visitor);
  
  // True if any change was made during the visit
  if (visitor.changed) {
    try {
      IDocument document = getDocument(unit);
      TextEdit textEdits = rewrite.rewriteAST(document, null);
      textEdits.apply(document);
    } catch (MalformedTreeException | BadLocationException e) {
      e.printStackTrace();
    }

  }
}


I run this in debug and the change is indeed happening in the node, as the code from the first post shows. Do I need anything other than rewriteAST and apply?

edit: When I try to do "astRoot.rewrite(document, null);" it throws "java.lang.IllegalArgumentException: Document does not match the AST"

[Updated on: Thu, 12 June 2014 10:01]

Report message to a moderator

Re: How to change the superclass extended by a type? [message #1385934 is a reply to message #1385925] Thu, 12 June 2014 11:01 Go to previous messageGo to next message
Stephan Herrmann is currently offline Stephan HerrmannFriend
Messages: 1853
Registered: July 2009
Senior Member
If you see non-empty textEdits, you're almost there Smile

Next questions:
How did you obtain the ICompilationUnit? Is it a workingCopy?
If you run your code from within an editor of a runtime workbench, can you see the changes in the editor?
To make them persistent in the file system I think you just have to save the unit.

It seems we skipped that in the tutorial, because things like quick fixes only have to produce the rewrite and from there on the framework will do the rest ...


Stephan
Re: How to change the superclass extended by a type? [message #1385941 is a reply to message #1385934] Thu, 12 June 2014 11:43 Go to previous messageGo to next message
Joao L. is currently offline Joao L.Friend
Messages: 6
Registered: June 2014
Junior Member
Thanks for the fast reply!
As for obtaining the ICompilationUnit, I'm parsing a project and loading each class within each package with the following code. I know this works because I'm able to change the imports of those classes using just "unit.createImport(newImport, null);". I don't use the AST to change the imports and I don't save the compilation unit.

IPackageFragment[] packages = newJavaProject.getPackageFragments();
for (IPackageFragment aPackage : packages) {
  if (aPackage.getKind() == IPackageFragmentRoot.K_SOURCE) {
    // The compilation unit is a class
    for (ICompilationUnit unit : aPackage.getCompilationUnits()) {
      replaceImports(unit); // Replaces imports and sometimes changes the superclass
    }
  }
}


edit: It seems my TextEdit is actually emtpy (prints "{MultiTextEdit} [0,0] [undefined]")... But I'm changing the super class inside the ASTVisitor.

[Updated on: Thu, 12 June 2014 12:01]

Report message to a moderator

Re: How to change the superclass extended by a type? [message #1385947 is a reply to message #1385941] Thu, 12 June 2014 12:18 Go to previous messageGo to next message
Stephan Herrmann is currently offline Stephan HerrmannFriend
Messages: 1853
Registered: July 2009
Senior Member
Oops, seeing that your TextEdits are empty, I re-read your previous code, and see that you are mixing the two styles of rewriting:

  • by astRoot.recordModifications(); you request the modifications should be recorded internally
  • by ASTRewrite.create(astRoot.getAST()); you create an external rewrite


for the first approach you'd need to call rewrite on the CompilationUnit (astRoot), the same object on which you called recordModifications().

The second approach is actually recommended, but then you'd need to pass the rewrite into your visitor and use operations like ASTRewrite#replace() instead of direct manipulation of the AST.

In your version, the external rewrite doesn't have any modifications, those are stored in the internal rewrite (AST#rewrite).

Stephan
Re: How to change the superclass extended by a type? [message #1385951 is a reply to message #1385947] Thu, 12 June 2014 12:34 Go to previous messageGo to next message
Joao L. is currently offline Joao L.Friend
Messages: 6
Registered: June 2014
Junior Member
I still get "Document does not match the AST". I wonder if I'm getting the document correctly?

ITextFileBufferManager textFileBufferManager =
  FileBuffers.getTextFileBufferManager();
try {
  IPath path = unit.getPath();
  textFileBufferManager.connect(path, LocationKind.IFILE, null);
  ITextFileBuffer textFileBuffer = textFileBufferManager.getTextFileBuffer(unit.getPath(), LocationKind.IFILE);
  IDocument document = textFileBuffer.getDocument();
  return document;
} catch (CoreException e) {
  e.printStackTrace();
  return null;
}

[Updated on: Thu, 12 June 2014 12:36]

Report message to a moderator

Re: How to change the superclass extended by a type? [message #1385959 is a reply to message #1385951] Thu, 12 June 2014 13:25 Go to previous messageGo to next message
Stephan Herrmann is currently offline Stephan HerrmannFriend
Messages: 1853
Registered: July 2009
Senior Member
Sorry, I have little experience in manually getting a document. For operations that work in the context of an editor, you can either ask
ITextViewer.getDocument()

or
JavaUI.getDocumentProvider().getDocument(editor.getEditorInput());


As to the IllegalArgumentException: the interesting part is the inner exception (cause).
Re: How to change the superclass extended by a type? [message #1385984 is a reply to message #1385934] Thu, 12 June 2014 16:10 Go to previous messageGo to next message
Joao L. is currently offline Joao L.Friend
Messages: 6
Registered: June 2014
Junior Member
Here's the full stack trace:

org.eclipse.e4.core.di.InjectionException: java.lang.IllegalArgumentException: Document does not match the AST
	at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:63)
	at org.eclipse.e4.core.internal.di.InjectorImpl.invokeUsingClass(InjectorImpl.java:243)
	at org.eclipse.e4.core.internal.di.InjectorImpl.invoke(InjectorImpl.java:224)
	at org.eclipse.e4.core.contexts.ContextInjectionFactory.invoke(ContextInjectionFactory.java:132)
	at org.eclipse.e4.core.commands.internal.HandlerServiceHandler.execute(HandlerServiceHandler.java:167)
	at org.eclipse.core.commands.Command.executeWithChecks(Command.java:499)
	at org.eclipse.core.commands.ParameterizedCommand.executeWithChecks(ParameterizedCommand.java:508)
	at org.eclipse.e4.core.commands.internal.HandlerServiceImpl.executeHandler(HandlerServiceImpl.java:213)
	at org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem.executeItem(HandledContributionItem.java:850)
	at org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem.handleWidgetSelection(HandledContributionItem.java:743)
	at org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem.access$7(HandledContributionItem.java:727)
	at org.eclipse.e4.ui.workbench.renderers.swt.HandledContributionItem$4.handleEvent(HandledContributionItem.java:662)
	at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:84)
	at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:1392)
	at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3742)
	at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:3363)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine$9.run(PartRenderingEngine.java:1113)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.e4.ui.internal.workbench.swt.PartRenderingEngine.run(PartRenderingEngine.java:997)
	at org.eclipse.e4.ui.internal.workbench.E4Workbench.createAndRunUI(E4Workbench.java:140)
	at org.eclipse.ui.internal.Workbench$5.run(Workbench.java:611)
	at org.eclipse.core.databinding.observable.Realm.runWithDefault(Realm.java:332)
	at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.java:567)
	at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:150)
	at org.eclipse.ui.internal.ide.application.IDEApplication.start(IDEApplication.java:124)
	at org.eclipse.equinox.internal.app.EclipseAppHandle.run(EclipseAppHandle.java:196)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.runApplication(EclipseAppLauncher.java:110)
	at org.eclipse.core.runtime.internal.adaptor.EclipseAppLauncher.start(EclipseAppLauncher.java:79)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:354)
	at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.java:181)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.eclipse.equinox.launcher.Main.invokeFramework(Main.java:636)
	at org.eclipse.equinox.launcher.Main.basicRun(Main.java:591)
	at org.eclipse.equinox.launcher.Main.run(Main.java:1450)
	at org.eclipse.equinox.launcher.Main.main(Main.java:1426)
Caused by: java.lang.IllegalArgumentException: Document does not match the AST
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.handleException(ASTRewriteAnalyzer.java:3731)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.visit(ASTRewriteAnalyzer.java:1850)
	at org.eclipse.jdt.core.dom.ReturnStatement.accept0(ReturnStatement.java:134)
	at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2514)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doVisit(ASTRewriteAnalyzer.java:357)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.voidVisitList(ASTRewriteAnalyzer.java:395)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.voidVisit(ASTRewriteAnalyzer.java:389)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doVisitUnchangedChildren(ASTRewriteAnalyzer.java:402)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.visit(ASTRewriteAnalyzer.java:1821)
	at org.eclipse.jdt.core.dom.Block.accept0(Block.java:134)
	at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2514)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.voidVisit(ASTRewriteAnalyzer.java:381)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.voidVisit(ASTRewriteAnalyzer.java:387)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doVisitUnchangedChildren(ASTRewriteAnalyzer.java:402)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.visit(ASTRewriteAnalyzer.java:1765)
	at org.eclipse.jdt.core.dom.MethodDeclaration.accept0(MethodDeclaration.java:489)
	at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2514)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doVisit(ASTRewriteAnalyzer.java:357)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doVisitList(ASTRewriteAnalyzer.java:375)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doVisit(ASTRewriteAnalyzer.java:366)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.rewriteParagraphList(ASTRewriteAnalyzer.java:1097)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.visit(ASTRewriteAnalyzer.java:1727)
	at org.eclipse.jdt.core.dom.TypeDeclaration.accept0(TypeDeclaration.java:467)
	at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2514)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doVisit(ASTRewriteAnalyzer.java:357)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.voidVisitList(ASTRewriteAnalyzer.java:395)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.voidVisit(ASTRewriteAnalyzer.java:389)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.doVisitUnchangedChildren(ASTRewriteAnalyzer.java:402)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.visit(ASTRewriteAnalyzer.java:1589)
	at org.eclipse.jdt.core.dom.CompilationUnit.accept0(CompilationUnit.java:222)
	at org.eclipse.jdt.core.dom.ASTNode.accept(ASTNode.java:2514)
	at org.eclipse.jdt.core.dom.InternalASTRewrite.rewriteAST(InternalASTRewrite.java:100)
	at org.eclipse.jdt.core.dom.AST.rewrite(AST.java:2867)
	at org.eclipse.jdt.core.dom.CompilationUnit.rewrite(CompilationUnit.java:940)
	at plugin.Utils.setSuperclass(Utils.java:97)
	at massim2dev.model.JADEProjectModel.replaceImports(JADEProjectModel.java:253)
	at massim2dev.model.JADEProjectModel.replaceImports(JADEProjectModel.java:228)
	at plugin.handlers.SJHandler.execute(SJHandler.java:47)
	at org.eclipse.ui.internal.handlers.HandlerProxy.execute(HandlerProxy.java:290)
	at org.eclipse.ui.internal.handlers.E4HandlerProxy.execute(E4HandlerProxy.java:90)
	at sun.reflect.GeneratedMethodAccessor35.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:606)
	at org.eclipse.e4.core.internal.di.MethodRequestor.execute(MethodRequestor.java:56)
	... 37 more
Caused by: org.eclipse.core.runtime.CoreException: End Of File
	at org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner.readNext(TokenScanner.java:92)
	at org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner.readToToken(TokenScanner.java:149)
	at org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner.readToToken(TokenScanner.java:162)
	at org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner.getTokenEndOffset(TokenScanner.java:187)
	at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.visit(ASTRewriteAnalyzer.java:1840)
	... 79 more
Re: How to change the superclass extended by a type? [message #1386009 is a reply to message #1385984] Thu, 12 June 2014 21:11 Go to previous message
Stephan Herrmann is currently offline Stephan HerrmannFriend
Messages: 1853
Registered: July 2009
Senior Member
Quote:

Caused by: org.eclipse.core.runtime.CoreException: End Of File
at org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner.readNext(TokenScanner.java:92)
at org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner.readToToken(TokenScanner.java:149)
at org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner.readToToken(TokenScanner.java:162)
at org.eclipse.jdt.internal.core.dom.rewrite.TokenScanner.getTokenEndOffset(TokenScanner.java:187)
at org.eclipse.jdt.internal.core.dom.rewrite.ASTRewriteAnalyzer.visit(ASTRewriteAnalyzer.java:1840)
... 79 more


have a look at the Scanner inside that TokenScanner: does it have the expected content? (us its toString() output in the debugger).
S.
Previous Topic:Java8 Nullness type qualifiers and Maps
Next Topic:escape characters syntax highlighting
Goto Forum:
  


Current Time: Sat Jul 27 10:33:48 GMT 2024

Powered by FUDForum. Page generated in 0.04299 seconds
.:: Contact :: Home ::.

Powered by: FUDforum 3.0.2.
Copyright ©2001-2010 FUDforum Bulletin Board Software

Back to the top