diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/ToYamlConverter.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/ToYamlConverter.groovy deleted file mode 100644 index 6f012b3b1a..0000000000 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/ToYamlConverter.groovy +++ /dev/null @@ -1,112 +0,0 @@ -/* - * Copyright 2013-2020 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.springframework.cloud.contract.verifier.converter - -import java.nio.file.Files - -import groovy.transform.CompileStatic -import groovy.util.logging.Commons - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.spec.ContractConverter -import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter -import org.springframework.core.io.support.SpringFactoriesLoader - -/** - * Converts contracts to YAML for the given folder - * - * @author Marcin Grzejszczak - * @since 2.1.0 - */ -@CompileStatic -@Commons -class ToYamlConverter { - - private ToYamlConverter() { - throw new IllegalStateException("Can't instantiate a utility class") - } - - private static YamlContractConverter yamlContractConverter = new YamlContractConverter() - - private static final List CONTRACT_CONVERTERS = converters() - - protected static void doReplaceContractWithYaml(ContractConverter converter, File file) { - // base dir: target/copied_contracts/contracts/ - // target/copied_contracts/contracts/foo/baz/bar.groovy - Collection collection = converter.convertFrom(file) - if (log.isDebugEnabled()) { - log.debug("Converted file [" + file + "] to collection of [" - + collection. - size() - + "] contracts") - } - List yamls = yamlContractConverter.convertTo(collection) - if (log.isDebugEnabled()) { - log.debug("Converted collection of [" - + collection. - size() - + "] contracts to [" - + yamls.size() - + "] YAML contracts") - } - // rm target/copied_contracts/contracts/foo/baz/bar.groovy - file.delete() - // [contracts/foo/baz/bar.groovy] -> [contracts/foo/baz/bar.yml] - Map stored = yamlContractConverter.store(yamls) - if (log.isDebugEnabled()) { - log.debug("Dumped YAMLs to following file names " + stored.keySet()) - } - stored.entrySet().each { - File ymlContractVersion = new File(file.parentFile, it.getKey()) - // store the YMLs instead of groovy files - Files.write(ymlContractVersion.toPath(), it.getValue()) - if (log.isDebugEnabled()) { - log.debug("Written file [" + ymlContractVersion + "] with YAML contract definition") - } - } - } - - /** - * If a contract ends with e.g. [.groovy] we will move it to the [original] - * folder, convert the [.groovy] version to [.yml] and store it instead - * of the Groovy file. From that we will continue processing as if - * from the very beginning there was only a [.yml] file - * - * @param baseDir - */ - static void replaceContractWithYaml(File baseDir) { - baseDir.eachFileRecurse { File file -> - ContractConverter converter = CONTRACT_CONVERTERS.find { - it.isAccepted(file) - } - if (converter) { - if (log.isDebugEnabled()) { - log.debug("Will replace contract [${file.name}] with a YAML version") - } - doReplaceContractWithYaml(converter, file) - } - } - } - - private static List converters() { - List converters = - SpringFactoriesLoader.loadFactories(ContractConverter, null) - converters.add(YamlContractConverter.INSTANCE) - converters.add(ContractVerifierDslConverter.INSTANCE) - return converters - } -} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy deleted file mode 100644 index 48e333588b..0000000000 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.groovy +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2013-2020 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.springframework.cloud.contract.verifier.converter - - -import com.fasterxml.jackson.dataformat.yaml.YAMLMapper -import groovy.transform.CompileStatic -import groovy.util.logging.Slf4j - -import org.springframework.cloud.contract.spec.Contract -import org.springframework.cloud.contract.spec.ContractConverter -/** - * Simple converter from and to a {@link YamlContract} to a collection of {@link Contract} - * - * @since 1.2.1 - * @author Marcin Grzejszczak - * @author Tim Ysewyn - */ -@Slf4j -@CompileStatic -class YamlContractConverter implements ContractConverter> { - - public static final YamlContractConverter INSTANCE = new YamlContractConverter() - private final YAMLMapper mapper = new YAMLMapper() - private final YamlToContracts yamlToContracts = new YamlToContracts() - private final ContractsToYaml contractsToYaml = new ContractsToYaml() - - @Override - boolean isAccepted(File file) { - String name = file.getName() - boolean acceptFile = name.endsWith(".yml") || name.endsWith(".yaml") - if (acceptFile){ - try { - this.yamlToContracts.convertFrom(file) - } catch (e) { - log.warn("Error Processing yaml file. Skipping Contract Generation ", e) - acceptFile = false - } - } - return acceptFile - } - - @Override - Collection convertFrom(File file) { - return this.yamlToContracts.convertFrom(file) - } - - @Override - List convertTo(Collection contracts) { - return this.contractsToYaml.convertTo(contracts) - } - - @Override - Map store(List contracts) { - return contracts.collectEntries { - return [(name(it)): - this.mapper.writeValueAsString(it).bytes] - } - } - - @Override - List read(byte[] bytes) { - try { - return Collections.singletonList(this.mapper.readValue(bytes, YamlContract)) - } catch (Exception e) { - return this.mapper.readerForListOf(YamlContract.class).readValue(bytes) - } - } - - protected String name(YamlContract contract) { - return (contract.name ?: - String.valueOf(Math.abs(contract.hashCode()))) + ".yml" - } -} diff --git a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/NamesUtil.groovy b/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/NamesUtil.groovy deleted file mode 100644 index 7cd84da33d..0000000000 --- a/spring-cloud-contract-verifier/src/main/groovy/org/springframework/cloud/contract/verifier/util/NamesUtil.groovy +++ /dev/null @@ -1,208 +0,0 @@ -/* - * Copyright 2013-2020 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.springframework.cloud.contract.verifier.util - -import java.nio.file.FileVisitResult -import java.nio.file.Files -import java.nio.file.Path -import java.nio.file.SimpleFileVisitor -import java.nio.file.attribute.BasicFileAttributes - -/** - * A utility class that helps to convert names - * - * @author Jakub Kubrynski, codearte.io - * - * @since 1.0.0 - */ -class NamesUtil { - - /** - * Returns the first element before the last separator presence. - * @return empty string if separator is not found. - */ - static String beforeLast(String string, String separator) { - if (string?.indexOf(separator) > -1) { - return string.substring(0, string.lastIndexOf(separator)) - } - return '' - } - - /** - * Returns the first element after the last separator presence - * @return the provided string if separator is not found. - */ - static String afterLast(String string, String separator) { - if (hasSeparator(string, separator)) { - return string.substring(string.lastIndexOf(separator) + 1) - } - return string - } - - /** - * Returns {@code true} if has a separatot in the string - */ - static boolean hasSeparator(String string, String separator) { - return string?.indexOf(separator) > -1 - } - - /** - * Returns the first element after the last dot presence - * @return the provided string if separator is not found. - */ - static String afterLastDot(String string) { - return afterLast(string, '.') - } - - /** - * @return {@code true} if has a dot - */ - static boolean hasDot(String string) { - return hasSeparator(string, '.') - } - - /** - * @param file - file with contracts - * @param contracts - collection of contracts - * @param counter - given contract index - * @return the default contract name, resolved from file name, taking - * * into consideration also the index of contract (for multiple contracts - * * stored in a single file). - */ - static String defaultContractName(File file, Collection contracts, int counter) { - String tillExtension = file.name.substring(0, file.name.lastIndexOf(".")) - return tillExtension + (counter > 0 || contracts.size() > 1 ? "_" + counter : "") - } - - /** - * Converts a string into a camel case format - */ - static String camelCase(String className) { - if (!className) { - return className - } - String firstChar = className.charAt(0).toLowerCase() as String - return firstChar + className.substring(1) - } - - /** - * Capitalizes the provided string - */ - static String capitalize(String className) { - if (!className) { - return className - } - String firstChar = className.charAt(0).toUpperCase() as String - return firstChar + className.substring(1) - } - - /** - * Returns the whole string to the last present dot. - * @return input string if there is no dot - */ - static String toLastDot(String string) { - if (string?.indexOf('.') > -1) { - return string.substring(0, string.lastIndexOf('.')) - } - return string - } - - /** - * Converts the Java package notation to a path format - */ - static String packageToDirectory(String packageName) { - return packageName.replace('.' as char, File.separatorChar) - } - - /** - * Converts the path format to a Java package notation - */ - static String directoryToPackage(String directory) { - return directory - .replace('.', '_') - .replace(File.separator, '.') - .replaceAll('\\.([0-9])', '._$1') - .replaceAll('^([0-9].*)', '_$1') - } - - /** - * Traverses the directories and converts renames illegal folder names - * to package names - * - * @param rootDir - folder from which to start traversing - */ - static void recrusiveDirectoryToPackage(File rootDir) { - try { - if (!rootDir.exists()) { - return - } - InvalidFolderRenamer renamer = new InvalidFolderRenamer() - Files.walkFileTree(rootDir.toPath(), renamer) - renamer.rename() - } - catch (IOException ex) { - throw new IllegalStateException(ex) - } - } - - private static class InvalidFolderRenamer extends SimpleFileVisitor { - - private Deque filesToRename = new ArrayDeque<>() - - @Override - FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { - String name = dir.toFile().getName() - String convertedName = directoryToPackage(name) - if (name != convertedName) { - this.filesToRename. - addFirst(new FileAndNewName(dir.toFile(), convertedName)) - } - return FileVisitResult.CONTINUE - } - - void rename() { - this.filesToRename.each { - it.file.renameTo(new File(it.file.parentFile, it.newName)) - } - } - } - - private static class FileAndNewName { - private final File file - private final String newName - - private FileAndNewName(File file, String newName) { - this.file = file - this.newName = newName - } - } - - /** - * Converts illegal package characters to underscores - */ - static String convertIllegalPackageChars(String packageName) { - return packageName.replaceAll('[_\\- .+]', '_') - } - - /** - * Converts illegal characters in method names to underscores - */ - static String convertIllegalMethodNameChars(String methodName) { - String result = methodName.replaceAll('^[^a-zA-Z_$0-9]', '_') - return result.replaceAll('[^a-zA-Z_$0-9]', '_') - } -} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ToYamlConverter.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ToYamlConverter.java new file mode 100644 index 0000000000..e2a98d4b39 --- /dev/null +++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/ToYamlConverter.java @@ -0,0 +1,121 @@ +/* + * Copyright 2013-2020 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.springframework.cloud.contract.verifier.converter; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.contract.spec.Contract; +import org.springframework.cloud.contract.spec.ContractConverter; +import org.springframework.cloud.contract.verifier.util.ContractVerifierDslConverter; +import org.springframework.core.io.support.SpringFactoriesLoader; + +/** + * Converts contracts to YAML for the given folder. + * + * @author Marcin Grzejszczak + * @since 2.1.0 + */ +public final class ToYamlConverter { + + private static final Logger log = LoggerFactory.getLogger(ToYamlConverter.class); + + private ToYamlConverter() { + throw new IllegalStateException("Can't instantiate a utility class"); + } + + private static final YamlContractConverter yamlContractConverter = new YamlContractConverter(); + + private static final List CONTRACT_CONVERTERS = converters(); + + protected static void doReplaceContractWithYaml(ContractConverter converter, + File file) { + if (log.isDebugEnabled()) { + log.debug("Will replace contract [{}] with a YAML version", file.getName()); + } + // base dir: target/copied_contracts/contracts/ + // target/copied_contracts/contracts/foo/baz/bar.groovy + Collection collection = converter.convertFrom(file); + if (log.isDebugEnabled()) { + log.debug("Converted file [{}] to collection of [{}] contracts", file, + collection.size()); + } + List yamls = yamlContractConverter.convertTo(collection); + if (log.isDebugEnabled()) { + log.debug("Converted collection of [{}] contracts to [{}] YAML contracts", + collection.size(), yamls.size()); + } + // rm target/copied_contracts/contracts/foo/baz/bar.groovy + file.delete(); + // [contracts/foo/baz/bar.groovy] -> [contracts/foo/baz/bar.yml] + Map stored = yamlContractConverter.store(yamls); + if (log.isDebugEnabled()) { + log.debug("Dumped YAMLs to following file names {}", stored.keySet()); + } + stored.forEach((key, value) -> { + File ymlContractVersion = new File(file.getParentFile(), key); + // store the YMLs instead of groovy files + try { + Files.write(ymlContractVersion.toPath(), value); + } + catch (IOException e) { + throw new RuntimeException(e); + } + if (log.isDebugEnabled()) { + log.debug("Written file [{}] with YAML contract definition", + ymlContractVersion); + } + }); + } + + /** + * If a contract ends with e.g. [.groovy] we will move it to the [original] folder, + * convert the [.groovy] version to [.yml] and store it instead of the Groovy file. + * From that we will continue processing as if from the very beginning there was only + * a [.yml] file + * @param baseDir base directory for contracts + */ + public static void replaceContractWithYaml(File baseDir) { + try { + Files.walk(baseDir.toPath()).map(Path::toFile) + .forEach(file -> CONTRACT_CONVERTERS.stream() + .filter(converter -> converter.isAccepted(file)).findFirst() + .ifPresent(converter -> doReplaceContractWithYaml(converter, + file))); + } + catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static List converters() { + List converters = SpringFactoriesLoader + .loadFactories(ContractConverter.class, null); + converters.add(YamlContractConverter.INSTANCE); + converters.add(ContractVerifierDslConverter.INSTANCE); + return converters; + } + +} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContract.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContract.java index 65544c37ff..b53942d0dd 100644 --- a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContract.java +++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContract.java @@ -429,6 +429,13 @@ public class YamlContract { public PredefinedRegex predefined; + public ValueMatcher() { + } + + public ValueMatcher(String regex) { + this.regex = regex; + } + @Override public boolean equals(Object o) { if (this == o) { diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.java new file mode 100644 index 0000000000..2466c452e7 --- /dev/null +++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/converter/YamlContractConverter.java @@ -0,0 +1,118 @@ +/* + * Copyright 2013-2020 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.springframework.cloud.contract.verifier.converter; + +import java.io.File; +import java.io.IOException; +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.dataformat.yaml.YAMLMapper; +import org.apache.commons.lang3.StringUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import org.springframework.cloud.contract.spec.Contract; +import org.springframework.cloud.contract.spec.ContractConverter; + +import static java.util.Collections.singletonList; +import static java.util.stream.Collectors.toMap; + +/** + * Simple converter from and to a {@link YamlContract} to a collection of + * {@link Contract}. + * + * @author Marcin Grzejszczak + * @author Tim Ysewyn + * @since 1.2.1 + */ +public class YamlContractConverter implements ContractConverter> { + + private static final Logger log = LoggerFactory + .getLogger(YamlContractConverter.class); + + public static final YamlContractConverter INSTANCE = new YamlContractConverter(); + + private final YAMLMapper mapper = new YAMLMapper(); + + private final YamlToContracts yamlToContracts = new YamlToContracts(); + + private final ContractsToYaml contractsToYaml = new ContractsToYaml(); + + @Override + public boolean isAccepted(File file) { + String name = file.getName(); + boolean acceptFile = name.endsWith(".yml") || name.endsWith(".yaml"); + if (acceptFile) { + try { + this.yamlToContracts.convertFrom(file); + } + catch (Exception e) { + log.warn("Error Processing yaml file. Skipping Contract Generation ", e); + acceptFile = false; + } + } + return acceptFile; + } + + @Override + public Collection convertFrom(File file) { + return this.yamlToContracts.convertFrom(file); + } + + @Override + public List convertTo(Collection contracts) { + return this.contractsToYaml.convertTo(contracts); + } + + @Override + public Map store(List contracts) { + return contracts.stream().collect(toMap(this::name, this::getBytes)); + } + + @Override + public List read(byte[] bytes) { + try { + return singletonList(this.mapper.readValue(bytes, YamlContract.class)); + } + catch (Exception e) { + try { + return this.mapper.readerForListOf(YamlContract.class).readValue(bytes); + } + catch (IOException ioException) { + throw new RuntimeException(ioException); + } + } + } + + protected String name(YamlContract contract) { + return StringUtils.defaultIfEmpty(contract.name, + String.valueOf(Math.abs((contract.hashCode())))) + ".yml"; + } + + protected byte[] getBytes(YamlContract yamlContract) { + try { + return this.mapper.writeValueAsString(yamlContract).getBytes(); + } + catch (JsonProcessingException e) { + throw new RuntimeException(e); + } + } + +} diff --git a/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/NamesUtil.java b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/NamesUtil.java new file mode 100644 index 0000000000..21e5db113c --- /dev/null +++ b/spring-cloud-contract-verifier/src/main/java/org/springframework/cloud/contract/verifier/util/NamesUtil.java @@ -0,0 +1,225 @@ +/* + * Copyright 2013-2020 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.springframework.cloud.contract.verifier.util; + +import java.io.File; +import java.io.IOException; +import java.nio.file.FileVisitResult; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Deque; + +/** + * A utility class that helps to convert names. + * + * @author Jakub Kubrynski, codearte.io + * @since 1.0.0 + */ +public final class NamesUtil { + + private NamesUtil() { + throw new IllegalStateException("Can't instantiate a utility class"); + } + + /** + * Returns the first element before the last separator presence. + * @return empty string if separator is not found. + */ + public static String beforeLast(String string, String separator) { + if (string != null && string.indexOf(separator) > -1) { + return string.substring(0, string.lastIndexOf(separator)); + } + return ""; + } + + /** + * Returns the first element after the last separator presence. + * @return the provided string if separator is not found. + */ + public static String afterLast(String string, String separator) { + if (hasSeparator(string, separator)) { + return string.substring(string.lastIndexOf(separator) + 1); + } + return string; + } + + /** + * Returns {@code true} if has a separatot in the string. + */ + public static boolean hasSeparator(String string, String separator) { + return string.indexOf(separator) > -1; + } + + /** + * Returns the first element after the last dot presence. + * @return the provided string if separator is not found. + */ + public static String afterLastDot(String string) { + return afterLast(string, "."); + } + + /** + * @return {@code true} if has a dot + */ + public static boolean hasDot(String string) { + return hasSeparator(string, "."); + } + + /** + * @param file - file with contracts + * @param contracts - collection of contracts + * @param counter - given contract index + * @return the default contract name, resolved from file name, taking * into + * consideration also the index of contract (for multiple contracts * stored in a + * single file). + */ + public static String defaultContractName(File file, Collection contracts, + int counter) { + int lastIndexOfDot = file.getName().lastIndexOf("."); + String tillExtension = file.getName().substring(0, lastIndexOfDot); + return tillExtension + (counter > 0 || contracts.size() > 1 ? "_" + counter : ""); + } + + /** + * Converts a string into a camel case format. + */ + public static String camelCase(String className) { + if (isEmpty(className)) { + return className; + } + String firstChar = className.substring(0, 1).toLowerCase(); + return firstChar + className.substring(1); + } + + /** + * Capitalizes the provided string. + */ + public static String capitalize(String className) { + if (isEmpty(className)) { + return className; + } + String firstChar = className.substring(0, 1).toUpperCase(); + return firstChar + className.substring(1); + } + + public static boolean isEmpty(String string) { + return string == null || string.length() == 0; + } + + /** + * Returns the whole string to the last present dot. + * @return input string if there is no dot + */ + public static String toLastDot(String string) { + if (string.indexOf(".") > -1) { + return string.substring(0, string.lastIndexOf(".")); + } + return string; + } + + /** + * Converts the Java package notation to a path format. + */ + public static String packageToDirectory(String packageName) { + return packageName.replace('.', File.separatorChar); + } + + /** + * Converts the path format to a Java package notation. + */ + public static String directoryToPackage(String directory) { + return directory.replace('.', '_').replace(File.separatorChar, '.') + .replaceAll("\\.([0-9])", "._$1").replaceAll("^([0-9].*)", "_$1"); + } + + /** + * Traverses the directories and converts renames illegal folder names to package + * names. + * @param rootDir - folder from which to start traversing + */ + public static void recrusiveDirectoryToPackage(File rootDir) { + try { + if (!rootDir.exists()) { + return; + } + InvalidFolderRenamer renamer = new InvalidFolderRenamer(); + Files.walkFileTree(rootDir.toPath(), renamer); + renamer.rename(); + } + catch (IOException ex) { + throw new IllegalStateException(ex); + } + } + + /** + * Converts illegal package characters to underscores. + */ + public static String convertIllegalPackageChars(String packageName) { + return packageName.replaceAll("[_\\- .+]", "_"); + } + + /** + * Converts illegal characters in method names to underscores. + */ + public static String convertIllegalMethodNameChars(String methodName) { + String result = methodName.replaceAll("^[^a-zA-Z_$0-9]", "_"); + return result.replaceAll("[^a-zA-Z_$0-9]", "_"); + } + + private static class InvalidFolderRenamer extends SimpleFileVisitor { + + private final Deque filesToRename = new ArrayDeque(); + + @Override + public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) { + String name = dir.toFile().getName(); + String convertedName = directoryToPackage(name); + if (!name.equals(convertedName)) { + this.filesToRename + .addFirst(new FileAndNewName(dir.toFile(), convertedName)); + } + + return FileVisitResult.CONTINUE; + } + + public void rename() { + this.filesToRename.forEach(fileAndNewName -> { + fileAndNewName.file.renameTo(new File(fileAndNewName.file.getParentFile(), + fileAndNewName.newName)); + }); + } + + } + + private static final class FileAndNewName { + + private FileAndNewName(File file, String newName) { + this.file = file; + this.newName = newName; + } + + private final File file; + + private final String newName; + + } + +}