Convert from groovy to java (#1478)

This commit is contained in:
Anatolii Zhmaiev
2020-08-23 21:51:08 +03:00
committed by GitHub
parent de25234823
commit 883dc6a8ed
7 changed files with 471 additions and 408 deletions

View File

@@ -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<ContractConverter> 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<Contract> collection = converter.convertFrom(file)
if (log.isDebugEnabled()) {
log.debug("Converted file [" + file + "] to collection of ["
+ collection.
size()
+ "] contracts")
}
List<YamlContract> 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<String, byte[]> 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<ContractConverter> converters() {
List<ContractConverter> converters =
SpringFactoriesLoader.loadFactories(ContractConverter, null)
converters.add(YamlContractConverter.INSTANCE)
converters.add(ContractVerifierDslConverter.INSTANCE)
return converters
}
}

View File

@@ -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<List<YamlContract>> {
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<Contract> convertFrom(File file) {
return this.yamlToContracts.convertFrom(file)
}
@Override
List<YamlContract> convertTo(Collection<Contract> contracts) {
return this.contractsToYaml.convertTo(contracts)
}
@Override
Map<String, byte[]> store(List<YamlContract> contracts) {
return contracts.collectEntries {
return [(name(it)):
this.mapper.writeValueAsString(it).bytes]
}
}
@Override
List<YamlContract> 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"
}
}

View File

@@ -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<Path> {
private Deque<FileAndNewName> 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]', '_')
}
}

View File

@@ -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<ContractConverter> 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<Contract> collection = converter.convertFrom(file);
if (log.isDebugEnabled()) {
log.debug("Converted file [{}] to collection of [{}] contracts", file,
collection.size());
}
List<YamlContract> 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<String, byte[]> 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<ContractConverter> converters() {
List<ContractConverter> converters = SpringFactoriesLoader
.loadFactories(ContractConverter.class, null);
converters.add(YamlContractConverter.INSTANCE);
converters.add(ContractVerifierDslConverter.INSTANCE);
return converters;
}
}

View File

@@ -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) {

View File

@@ -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<List<YamlContract>> {
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<Contract> convertFrom(File file) {
return this.yamlToContracts.convertFrom(file);
}
@Override
public List<YamlContract> convertTo(Collection<Contract> contracts) {
return this.contractsToYaml.convertTo(contracts);
}
@Override
public Map<String, byte[]> store(List<YamlContract> contracts) {
return contracts.stream().collect(toMap(this::name, this::getBytes));
}
@Override
public List<YamlContract> 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);
}
}
}

View File

@@ -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<Path> {
private final Deque<FileAndNewName> filesToRename = new ArrayDeque<FileAndNewName>();
@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;
}
}