ChangeBehavior.java
/*******************************************************************************
* Copyright (c) 2021 Carsten Hammer.
*
* 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:
* Carsten Hammer
*******************************************************************************/
package org.sandbox.jdt.internal.corext.fix.helper;
import static org.sandbox.jdt.internal.common.LibStandardNames.METHOD_DEFAULT_CHARSET;
import static org.sandbox.jdt.internal.common.LibStandardNames.METHOD_DISPLAY_NAME;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Locale;
import java.util.Map;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.FieldAccess;
import org.eclipse.jdt.core.dom.FieldDeclaration;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.Modifier;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.jdt.core.dom.VariableDeclarationFragment;
import org.eclipse.jdt.core.dom.rewrite.ImportRewrite;
import org.eclipse.jdt.internal.corext.dom.ASTNodeFactory;
import org.eclipse.jdt.internal.corext.refactoring.structure.CompilationUnitRewrite;
public enum ChangeBehavior {
KEEP_BEHAVIOR() {
@Override
protected Expression computeCharsetASTNode(final CompilationUnitRewrite cuRewrite, AST ast, String charset, Map<String, QualifiedName> charsetConstants) {
Expression callToCharsetDefaultCharset= null;
if (charset != null) {
callToCharsetDefaultCharset= addCharsetUTF8(cuRewrite, ast, charset);
} else {
// needs Java 1.5
callToCharsetDefaultCharset= addCharsetComputation(cuRewrite, ast);
}
return callToCharsetDefaultCharset;
}
@Override
protected String computeCharsetforPreview() {
String insert= "Charset.defaultCharset()"; //$NON-NLS-1$
return insert;
}
},
ENFORCE_UTF8() {
@Override
protected Expression computeCharsetASTNode(final CompilationUnitRewrite cuRewrite, AST ast, String charset, Map<String, QualifiedName> charsetConstants) {
String charset2= charset == null ? "UTF_8" : charset; //$NON-NLS-1$
Expression callToCharsetDefaultCharset= addCharsetUTF8(cuRewrite, ast, charset2);
return callToCharsetDefaultCharset;
}
@Override
protected String computeCharsetforPreview() {
String insert= "StandardCharsets.UTF_8"; //$NON-NLS-1$
return insert;
}
},
ENFORCE_UTF8_AGGREGATE() {
@Override
protected Expression computeCharsetASTNode(final CompilationUnitRewrite cuRewrite, AST ast, String charset2, Map<String, QualifiedName> charsetConstants) {
String charset= charset2 == null ? "UTF_8" : charset2; //$NON-NLS-1$
// Generate a valid Java identifier for the charset name (e.g., UTF_8)
String fieldName = charset.toUpperCase(Locale.ROOT).replace('-', '_');
// Check if this charset constant is already stored in the map
if (charsetConstants.containsKey(fieldName)) {
return charsetConstants.get(fieldName);
}
// Add import for StandardCharsets
ImportRewrite importRewrite = cuRewrite.getImportRewrite();
importRewrite.addImport(StandardCharsets.class.getCanonicalName());
importRewrite.addImport(Charset.class.getCanonicalName());
// Check if the static field already exists in the class
TypeDeclaration enclosingType = (TypeDeclaration) cuRewrite.getRoot().types().get(0);
FieldDeclaration existingField = findStaticCharsetField(enclosingType, fieldName);
QualifiedName fieldReference;
if (existingField == null) {
// Create a new static field if it doesn't exist
VariableDeclarationFragment fragment = ast.newVariableDeclarationFragment();
fragment.setName(ast.newSimpleName(fieldName));
fragment.setInitializer(createCharsetAccessExpression(ast, charset));
FieldDeclaration fieldDeclaration = ast.newFieldDeclaration(fragment);
fieldDeclaration.setType(ast.newSimpleType(ast.newName("Charset"))); //$NON-NLS-1$
fieldDeclaration.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.PRIVATE_KEYWORD));
fieldDeclaration.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.STATIC_KEYWORD));
fieldDeclaration.modifiers().add(ast.newModifier(Modifier.ModifierKeyword.FINAL_KEYWORD));
// Add the new field to the class
cuRewrite.getASTRewrite().getListRewrite(enclosingType, TypeDeclaration.BODY_DECLARATIONS_PROPERTY)
.insertFirst(fieldDeclaration, null);
// Create a QualifiedName to refer to this new field
fieldReference = ast.newQualifiedName(
ast.newSimpleName(enclosingType.getName().getIdentifier()),
ast.newSimpleName(fragment.getName().getIdentifier())
);
} else {
// If the field already exists, find its reference name
VariableDeclarationFragment fragment = (VariableDeclarationFragment) existingField.fragments().get(0);
fieldReference = ast.newQualifiedName(
ast.newSimpleName(enclosingType.getName().getIdentifier()),
fragment.getName()
);
}
// Cache the field reference in the map and return it
charsetConstants.put(fieldName, fieldReference);
return fieldReference;
}
@Override
protected String computeCharsetforPreview() {
return "CharsetConstant"; //$NON-NLS-1$
}
};
abstract protected Expression computeCharsetASTNode(CompilationUnitRewrite cuRewrite, AST ast, String charset, Map<String, QualifiedName> charsetConstants);
abstract protected String computeCharsetforPreview();
protected static FieldDeclaration findStaticCharsetField(TypeDeclaration type, String fieldName) {
for (FieldDeclaration field : type.getFields()) {
for (Object fragment : field.fragments()) {
if (fragment instanceof VariableDeclarationFragment) {
VariableDeclarationFragment varFrag = (VariableDeclarationFragment) fragment;
if (varFrag.getName().getIdentifier().equals(fieldName)) {
return field;
}
}
}
}
return null;
}
protected static Expression createCharsetAccessExpression(AST ast, String charset) {
FieldAccess fieldAccess = ast.newFieldAccess();
fieldAccess.setExpression(ast.newName(StandardCharsets.class.getSimpleName()));
fieldAccess.setName(ast.newSimpleName(charset));
return fieldAccess;
}
/**
* Create access to StandardCharsets.UTF_8, needs Java 1.7 or newer
*
* @param cuRewrite CompilationUnitRewrite
* @param ast AST
* @param charset Charset as String
* @return FieldAccess that returns Charset for UTF_8
*/
protected static FieldAccess addCharsetUTF8(CompilationUnitRewrite cuRewrite, AST ast, String charset) {
/**
* Add import java.nio.charset.StandardCharsets - available since Java 1.7
*/
ImportRewrite importRewrite= cuRewrite.getImportRewrite();
importRewrite.addImport(StandardCharsets.class.getCanonicalName());
/**
* Add field access to StandardCharsets.UTF_8
*/
FieldAccess fieldaccess= ast.newFieldAccess();
fieldaccess.setExpression(ASTNodeFactory.newName(ast, StandardCharsets.class.getSimpleName()));
fieldaccess.setName(ast.newSimpleName(charset));
return fieldaccess;
}
/**
* Create call to Charset.defaultCharset(), needs Java 1.5 or newer
*
* @param cuRewrite CompilationUnitRewrite
* @param ast AST
* @return MethodInvocation that returns Charset for platform encoding
*/
protected static MethodInvocation addCharsetComputation(final CompilationUnitRewrite cuRewrite, AST ast) {
/**
* Add import java.nio.charset.Charset
*/
ImportRewrite importRewrite= cuRewrite.getImportRewrite();
importRewrite.addImport(Charset.class.getCanonicalName());
/**
* Add call to Charset.defaultCharset() - this is available since Java 1.5
*/
MethodInvocation firstCall= ast.newMethodInvocation();
firstCall.setExpression(ASTNodeFactory.newName(ast, Charset.class.getSimpleName()));
firstCall.setName(ast.newSimpleName(METHOD_DEFAULT_CHARSET));
return firstCall;
}
/**
* Create call to Charset.defaultCharset().displayName(), needs Java 1.5 or newer
*
* @param cuRewrite CompilationUnitRewrite
* @param ast AST
* @param cb ChangeBehavior
* @param charset Charset as String
* @return MethodInvocation that returns String
*/
protected MethodInvocation addCharsetStringComputation(final CompilationUnitRewrite cuRewrite, AST ast, ChangeBehavior cb, String charset, Map<String, QualifiedName> charsetConstants) {
Expression callToCharsetDefaultCharset= computeCharsetASTNode(cuRewrite, ast, charset, charsetConstants);
/**
* Add second call to Charset.defaultCharset().displayName()
*/
MethodInvocation secondCall= ast.newMethodInvocation();
secondCall.setExpression(callToCharsetDefaultCharset);
secondCall.setName(ast.newSimpleName(METHOD_DISPLAY_NAME));
return secondCall;
}
}