修改 eclipse 默认的 toString 模板, 自动对敏感字段进行 *** 处理

本文介绍了如何修改Eclipse的源码,以实现自定义toString方法模板,包括选择StringBuilder/StringBuffer,每字段占一行,并自动对敏感字段进行***处理。涉及到的文件包括ToStringTemplateParser、ToStringGenerationSettings和StringBuilderGenerator。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

简介:
  eclipse 默认可以生成 toString 方法, 但是自动生成的代码有时候满足不了实际要求, 这里演示一下通过修改 eclipse 源码的方式来改变自动生成的 toString 方法.

1. 目标
1.1 将默认的 toString 模板修改为
  {${member.name()}=${member.value}, ${otherMembers}}
1.2 Code style 默认选中 StringBuilder/StringBuffer
1.3 toString 方法中每个字段占一行
1.4 toString 方法中自动对敏感字段进行 *** 处理
# 修改后截图如下:


2. 依赖 jar
eclipse_home\plugins\com.ibm.icu_50.1.1.v201304230130.jar
eclipse_home\plugins\org.eclipse.core.commands_3.6.100.v20130515-1857.jar
eclipse_home\plugins\org.eclipse.core.resources_3.8.101.v20130717-0806.jar
eclipse_home\plugins\org.eclipse.core.runtime_3.9.100.v20131218-1515.jar
eclipse_home\plugins\org.eclipse.equinox.common_3.6.200.v20130402-1505.jar
eclipse_home\plugins\org.eclipse.jdt.core_3.9.2.v20140114-1555.jar
eclipse_home\plugins\org.eclipse.jdt.ui_3.9.2.v20131106-1600.jar
eclipse_home\plugins\org.eclipse.jface_3.9.1.v20130725-1141.jar
eclipse_home\plugins\org.eclipse.swt.win32.win32.x86_3.102.1.v20140206-1358.jar
eclipse_home\plugins\org.eclipse.ui.workbench_3.105.2.v20140211-1711.jar


3. download eclipse source code
  http://archive.eclipse.org/eclipse/downloads/
  
4. 需要修改的文件
4.1 修改 toString 的默认模板
   org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.ToStringTemplateParser
   org.eclipse.jdt.internal.ui.dialogs.GenerateToStringDialog
   # GenerateToStringDialog 文件内容不需要修改, 只需要重新编译一下
   
4.2 Code style 默认选中 StringBuilder/StringBuffer
   org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.ToStringGenerationSettings
   
4.3 toString 方法中自动对敏感字段进行 *** 处理
   org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration.StringBuilderGenerator

/*******************************************************************************
 * Copyright (c) 2008, 2011 Mateusz Matela 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:
 *     Mateusz Matela <mateusz.matela@gmail.com> - [code manipulation] [dcr] toString() builder wizard - https://bugs.eclipse.org/bugs/show_bug.cgi?id=26070
 *******************************************************************************/
package org.eclipse.jdt.internal.corext.codemanipulation.tostringgeneration;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;

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.MethodInvocation;
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;


/**
 * <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() ? "sb" : "sb", 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());
	}
	
     以下为新添加的内容  //
    /**
     * 添加成员信息
     */
    @SuppressWarnings("unchecked")
    protected void addMember(Object member, boolean addSeparator) {
        flushBuffer(null);
        
        List<Object> objList = new ArrayList<Object>();
        Object fieldName = null;
        Object fieldValue = null;
        String templateElement = null;
        StringBuilder sb = new StringBuilder();
        
        String[] stringArray = this.fContext.getTemplateParser().getBody();
        for (int i = 0; i < stringArray.length; i++) {
            templateElement = stringArray[i];
            if (templateElement.equals("${member.name}") || templateElement.equals("${member.name()}")) {
                fieldName = processElement(stringArray[i], member);
                objList.add(fieldName);
                continue;
            } else if (templateElement == "${member.value}") {
                fieldValue = processElement(stringArray[i], member);
                if (isSensitiveField(fieldName)) {
                    fieldValue = "*******";
                }
                objList.add(fieldValue);
                continue;
            } else {
                objList.add(processElement(stringArray[i], member));
            }
        }
        if (addSeparator) {
            objList.add(this.fContext.getTemplateParser().getSeparator());
        }
        
        Expression currExpression = null;
        for (Object element : objList) {
            if (element instanceof String) {
                sb.append(element);
            } else if (element instanceof Expression) {
                if (sb.length() != 0) {
                    StringLiteral literal = this.fAst.newStringLiteral();
                    literal.setLiteralValue(sb.toString());
                    currExpression = getNextExpression(currExpression, literal);
                    sb.delete(0, sb.length());
                }
                currExpression = getNextExpression(currExpression, (Expression)element);
            }
        }
        if (sb.length() != 0) {
            StringLiteral literal = this.fAst.newStringLiteral();
            literal.setLiteralValue(sb.toString());
            currExpression = getNextExpression(currExpression, literal);
            sb.delete(0, sb.length());
        }
        this.toStringMethod.getBody().statements().add(this.fAst.newExpressionStatement(currExpression));
    }
    
    /**
     * 计算新的表达式
     * @param currExpression
     * @param argument
     * @return
     */
    @SuppressWarnings("unchecked")
    private Expression getNextExpression(Expression currExpression, Expression argument) {
        MethodInvocation invocation = this.fAst.newMethodInvocation();
        if (currExpression == null) {
            invocation.setExpression(this.fAst.newName(this.fBuilderVariableName));
        } else {
            invocation.setExpression(currExpression);
        }
        invocation.setName(this.fAst.newSimpleName("append"));
        invocation.arguments().add(argument);
        return invocation;
    }
    
    /**
     * 判断是否是敏感字段
     * @param fieldName
     * @return
     */
    private boolean isSensitiveField(Object fieldName) {
        String name = String.valueOf(fieldName).toLowerCase(Locale.US);
        String[] words = new String[]{"pass", "pwd", "session", "token"};
        for (String word : words) {
            if (name.contains(word)) {
                return true;
            }
        }
        return false;
    }
     end  //
}
5. 用编译出来的 *.class 文件替换 jar 包中的内容
   org.eclipse.jdt.ui_3.9.2.v20131106-1600.jar
   
### 自动生成 Java 类方法的工具 为了简化开发过程并提高效率,多种工具和插件可以自动生成 `getter`、`setter`、构造函数(包括全参构造器和无参构造器)、`toString()` 和 `equals()` 方法。 #### Lombok 注解库 Lombok 是一种流行的 Java 库,通过简单的注解来减少样板代码。使用 Lombok 可以显著降低编写这些常见方法的工作量: - **@Data**: 提供了 `getter`/`setter`、`toString()`、`equals()` 和 `hashCode()` 的实现[^1]。 注意:当使用 `@Data` 时,默认会为所有字段生成 `equals()` 和 `hashCode()` 实现,这可能导致意外行为,因此建议单独指定所需的组件[^4]。 - **@Getter/@Setter**: 单独为目标属性生成访问器或修改器方法。 - **@NoArgsConstructor**, **@AllArgsConstructor**, **@RequiredArgsConstructor**: 分别用于创建无参数构造函数、全部参数构造函数以及仅含必需字段的构造函数。 - **@ToString(includeFieldNames=true)** 或者更细粒度控制如 `@ToString(of={"field1", "field2"})`: 定制化输出字符串表示形式[^3]。 - **@EqualsAndHashCode(callSuper=false, of={"field1",...})**: 自定义比较逻辑而不依赖默认继承机制。 #### IDE 内置功能与插件支持 主流集成开发环境 (IDE),例如 IntelliJ IDEA 和 Eclipse 都内置了一定程度上的辅助生成功能;同时也有专门针对此目的设计的各种插件可用: - 支持一键生成上述提到的方法模板。 - 插件市场中有许多增强型插件可以帮助进一步优化这一流程,比如 “GenerateSerialVersionUID”。 - **Eclipse** - 同样具备类似的快捷键组合来自动生成所需代码片段。 - 社区贡献了许多实用的小工具,像 JAutodoc 就能在文档方面提供额外帮助。 对于希望保持项目轻量化而又不想牺牲生产力的人来说,合理利用 Lombok 结合强大 IDE 功能无疑是一个明智的选择。 ```java // 使用 Lombok 示例 import lombok.*; @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class Person { private String name; private int age; // 如果只需要部分字段参与 toString() @Override public String toString() { return "Person{" + "name='" + name + '\'' + '}'; } } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值