Copyright (c) 2008, 2019 Mateusz Matela 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:
Mateusz Matela - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070
Red Hat Inc. - moved to jdt.core.manipulation
/*******************************************************************************
* Copyright (c) 2008, 2019 Mateusz Matela 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:
* Mateusz Matela <mateusz.matela@gmail.com> - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070
* Red Hat Inc. - moved to jdt.core.manipulation
*******************************************************************************/
package org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.jdt.core.NamingConventions;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.Name;
import org.eclipse.jdt.core.dom.ReturnStatement;
import org.eclipse.jdt.core.dom.Statement;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.VariableDeclarationStatement;
import org.eclipse.jdt.core.dom.InfixExpression.Operator;
Implementation of AbstractToStringGenerator
that creates toString()
method using StringBuilder
(or StringBuffer
for old versions of JDK)
Generated methods look like this:
public String toString() {
StringBuilder builder= new StringBuilder();
builder.append("FooClass( field1=");
builder.append(field1);
builder.append(", field2=");
builder.append(field2);
builder.append(" )");
return builder.toString();
}
Since: 3.5
/**
* <p>
* Implementation of <code>AbstractToStringGenerator</code> that creates <code>toString()</code>
* method using <code>StringBuilder</code> (or <code>StringBuffer</code> for old versions of JDK)
* </p>
* <p>
* Generated methods look like this:
*
* <pre>
* public String toString() {
* StringBuilder builder= new StringBuilder();
* builder.append("FooClass( field1=");
* builder.append(field1);
* builder.append(", field2=");
* builder.append(field2);
* builder.append(" )");
* return builder.toString();
* }
* </pre>
*
* </p>
*
* @since 3.5
*/
public class StringBuilderGenerator extends AbstractToStringGenerator {
protected StringBuffer fBuffer;
protected String fBuilderVariableName;
protected final String APPEND_METHOD_NAME= "append"; //$NON-NLS-1$
protected void flushBuffer(Block target) {
if (fBuffer.length() > 0) {
StringLiteral literal= fAst.newStringLiteral();
literal.setLiteralValue(fBuffer.toString());
if (target == null)
target= toStringMethod.getBody();
target.statements().add(fAst.newExpressionStatement(createMethodInvocation(fBuilderVariableName, APPEND_METHOD_NAME, literal)));
fBuffer.setLength(0);
}
}
@Override
protected void initialize() {
super.initialize();
fBuilderVariableName= createNameSuggestion(getContext().is50orHigher() ? "builder" : "buffer", NamingConventions.VK_LOCAL); //$NON-NLS-1$ //$NON-NLS-2$
fBuffer= new StringBuffer();
VariableDeclarationFragment fragment= fAst.newVariableDeclarationFragment();
fragment.setName(fAst.newSimpleName(fBuilderVariableName));
ClassInstanceCreation classInstance= fAst.newClassInstanceCreation();
Name typeName= addImport(getContext().is50orHigher() ? "java.lang.StringBuilder" : "java.lang.StringBuffer"); //$NON-NLS-1$ //$NON-NLS-2$
classInstance.setType(fAst.newSimpleType(typeName));
fragment.setInitializer(classInstance);
VariableDeclarationStatement vStatement= fAst.newVariableDeclarationStatement(fragment);
vStatement.setType(fAst.newSimpleType((Name)ASTNode.copySubtree(fAst, typeName)));
toStringMethod.getBody().statements().add(vStatement);
}
@Override
protected void complete() throws CoreException {
flushBuffer(null);
super.complete();
ReturnStatement rStatement= fAst.newReturnStatement();
rStatement.setExpression(createMethodInvocation(fBuilderVariableName, "toString", null)); //$NON-NLS-1$
toStringMethod.getBody().statements().add(rStatement);
}
protected void addElement(Object element, Block block) {
if (element instanceof String)
fBuffer.append((String)element);
if (element instanceof Expression) {
flushBuffer(block);
block.statements().add(fAst.newExpressionStatement(createMethodInvocation(fBuilderVariableName, APPEND_METHOD_NAME, (Expression)element)));
}
}
@Override
protected void addMemberCheckNull(Object member, boolean addSeparator) {
IfStatement ifStatement= fAst.newIfStatement();
ifStatement.setExpression(createInfixExpression(createMemberAccessExpression(member, true, true), Operator.NOT_EQUALS, fAst.newNullLiteral()));
Block thenBlock= fAst.newBlock();
flushBuffer(null);
String[] arrayString= getContext().getTemplateParser().getBody();
for (int i= 0; i < arrayString.length; i++) {
addElement(processElement(arrayString[i], member), thenBlock);
}
if (addSeparator)
addElement(getContext().getTemplateParser().getSeparator(), thenBlock);
flushBuffer(thenBlock);
if (thenBlock.statements().size() == 1 && !getContext().isForceBlocks()) {
ifStatement.setThenStatement((Statement)ASTNode.copySubtree(fAst, (ASTNode)thenBlock.statements().get(0)));
} else {
ifStatement.setThenStatement(thenBlock);
}
toStringMethod.getBody().statements().add(ifStatement);
}
@Override
protected void addElement(Object element) {
addElement(element, toStringMethod.getBody());
}
}