diff --git a/rewrite-core/src/main/java/org/openrewrite/internal/NamingService.java b/rewrite-core/src/main/java/org/openrewrite/internal/NamingService.java new file mode 100644 index 00000000000..c8a1ddfb512 --- /dev/null +++ b/rewrite-core/src/main/java/org/openrewrite/internal/NamingService.java @@ -0,0 +1,22 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.internal; + +public interface NamingService { + + String standardizeMethodName(String oldMethodName); + +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/service/JavaNamingService.java b/rewrite-java/src/main/java/org/openrewrite/java/service/JavaNamingService.java new file mode 100644 index 00000000000..5f2e84e9c04 --- /dev/null +++ b/rewrite-java/src/main/java/org/openrewrite/java/service/JavaNamingService.java @@ -0,0 +1,67 @@ +/* + * Copyright 2023 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.service; + +import org.openrewrite.internal.NameCaseConvention; +import org.openrewrite.internal.NamingService; + +import java.util.regex.Pattern; + +public class JavaNamingService implements NamingService { + + private static final Pattern STANDARD_METHOD_NAME = Pattern.compile("^[a-z][a-zA-Z0-9]*$"); + private static final Pattern SNAKE_CASE = Pattern.compile("^[a-zA-Z0-9]+_\\w+$"); + + @Override + public String standardizeMethodName(String oldMethodName) { + if (!oldMethodName.startsWith("_") && + !STANDARD_METHOD_NAME.matcher(oldMethodName).matches()) { + StringBuilder result = new StringBuilder(); + if (SNAKE_CASE.matcher(oldMethodName).matches()) { + result.append(NameCaseConvention.format(NameCaseConvention.LOWER_CAMEL, oldMethodName)); + } else { + int nameLength = oldMethodName.length(); + for (int i = 0; i < nameLength; i++) { + char c = oldMethodName.charAt(i); + if (i == 0) { + // the java specification requires identifiers to start with [a-zA-Z$_] + if (c != '$' && c != '_') { + result.append(Character.toLowerCase(c)); + } + } else { + if (!Character.isLetterOrDigit(c)) { + while ((!Character.isLetterOrDigit(c) || c > 'z')) { + i++; + if (i < nameLength) { + c = oldMethodName.charAt(i); + } else { + break; + } + } + if (i < nameLength) { + result.append(Character.toUpperCase(c)); + } + } else { + result.append(c); + } + } + } + } + return result.toString(); + } + return oldMethodName; + } +} diff --git a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaSourceFile.java b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaSourceFile.java index 97f3551c473..d705a710f64 100644 --- a/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaSourceFile.java +++ b/rewrite-java/src/main/java/org/openrewrite/java/tree/JavaSourceFile.java @@ -18,12 +18,14 @@ import org.jspecify.annotations.Nullable; import org.openrewrite.Incubating; import org.openrewrite.SourceFile; +import org.openrewrite.internal.NamingService; import org.openrewrite.internal.WhitespaceValidationService; import org.openrewrite.java.internal.JavaWhitespaceValidationService; import org.openrewrite.java.internal.TypesInUse; import org.openrewrite.java.service.AnnotationService; import org.openrewrite.java.service.AutoFormatService; import org.openrewrite.java.service.ImportService; +import org.openrewrite.java.service.JavaNamingService; import java.lang.reflect.InvocationTargetException; import java.nio.file.Path; @@ -75,6 +77,8 @@ default T service(Class service) { } else if (WhitespaceValidationService.class.getName().equals(service.getName())) { // Only unit tests should need to use this service, so no classloading concerns return (T) new JavaWhitespaceValidationService(); + } else if (NamingService.class.getName().equals(service.getName())) { + return (T) new JavaNamingService(); } else { throw new UnsupportedOperationException("Service " + service + " not supported"); } diff --git a/rewrite-java/src/test/java/org/openrewrite/java/service/JavaNamingServiceTest.java b/rewrite-java/src/test/java/org/openrewrite/java/service/JavaNamingServiceTest.java new file mode 100644 index 00000000000..8a28a65d1ba --- /dev/null +++ b/rewrite-java/src/test/java/org/openrewrite/java/service/JavaNamingServiceTest.java @@ -0,0 +1,36 @@ +/* + * Copyright 2024 the original author or authors. + *

+ * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * https://www.apache.org/licenses/LICENSE-2.0 + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.openrewrite.java.service; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +import static org.assertj.core.api.Assertions.assertThat; + +class JavaNamingServiceTest { + + @ParameterizedTest + @CsvSource(textBlock = """ + foo_bar,fooBar + foo$bar,fooBar + foo_bar$,fooBar + foo$bar$,fooBar + """) + void changeMethodName(String before, String after) { + String actual = new JavaNamingService().standardizeMethodName(before); + assertThat(actual).isEqualTo(after); + } +}