)
19 | }
20 |
21 | dependencies {
22 | implementation(kotlin("stdlib-jdk8"))
23 | testImplementation ("org.junit.jupiter:junit-jupiter-api:${Versions.junitJupiter}")
24 | testImplementation ("org.junit.jupiter:junit-jupiter-params:${Versions.junitJupiter}")
25 | testImplementation("io.mockk:mockk:${Versions.mockk}")
26 |
27 | testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${Versions.junitJupiter}")
28 | }
29 |
--------------------------------------------------------------------------------
/detekt-config.yml:
--------------------------------------------------------------------------------
1 | build:
2 | maxIssues: 0
3 |
4 | complexity:
5 | TooManyFunctions:
6 | ignorePrivate: true
7 |
8 | exceptions:
9 | TooGenericExceptionCaught:
10 | active: true
11 | exceptionNames:
12 | - ArrayIndexOutOfBoundsException
13 | - Error
14 | - IllegalMonitorStateException
15 | - NullPointerException
16 | - IndexOutOfBoundsException
17 | - Throwable
18 |
19 | style:
20 | ForbiddenComment:
21 | active: false
22 | ThrowsCount:
23 | active: false
24 |
25 |
--------------------------------------------------------------------------------
/doc/README.adoc:
--------------------------------------------------------------------------------
1 | = LivingDoc 2 Developer Documentation
2 |
3 | This folder contains LD2 documentation relevant for developers.
4 |
--------------------------------------------------------------------------------
/doc/decisions/README.adoc:
--------------------------------------------------------------------------------
1 | = LivingDoc2 - Architecture Decision Record
2 |
3 | Here you have an overview of all Architecture Decision Records (ADR) created so far.
4 |
5 | * link:adr-001-keep-architecture-decision-records.adoc[ADR001 - Keep ADR's]
6 | * link:adr-002-use-asciidoc-markup.adoc[ADR002 - Use AsciiDoc as markup]
7 | * link:adr-003-use-gradle-as-build-tool.adoc[ADR003 - Use Gradle as build tool]
8 | * link:adr-004-implement-junit5-engine.adoc[ADR004 - Implement JUnit 5 Engine]
9 | * link:adr-005-use-java-spi.adoc[ADR005 - Use Java SPI]
10 |
--------------------------------------------------------------------------------
/doc/decisions/adr-002-use-asciidoc-markup.adoc:
--------------------------------------------------------------------------------
1 | = ADR 2: Use AsciiDoc Markup For Documentation
2 |
3 | == Context
4 |
5 | We want to create developer and end-user documentation in a textual format that
6 | we can manage alongside with code in git. Our experience suggests that it is
7 | easier to keep documentation in sync when we can keep it in version control
8 | with the code and edit it with the same tools.
9 |
10 | Markdown is a simple markup language that is widely supported and optimized for
11 | readability in text form without having to use a renderer. However, it lacks
12 | some features such as _includes_ (e.g. for code fragments) and _tables_.
13 |
14 | AsciiDoc is also widely adopted, but sacrifices some readability to support
15 | richer markup which includes the features we are missing in Markdown.
16 |
17 |
18 | == Decision
19 |
20 | We will use AsciiDoc as markup language for documentation.
21 |
22 | AsciiDoc text files should be properly formatted, so that they can be read
23 | without a renderer. They should wrap lines using hard line breaks after about
24 | 70 characters.
25 |
26 | We will render end-user documentation as HTML.
27 |
28 |
29 | == Status
30 |
31 | Accepted.
32 |
33 |
34 | == Consequences
35 |
36 | * We have support for _includes_ and _tables_.
37 | * Documentation is readable, with and without a renderer.
38 | * It is easier to update documentation alongside with the code.
39 |
--------------------------------------------------------------------------------
/doc/decisions/adr-003-use-gradle-as-build-tool.adoc:
--------------------------------------------------------------------------------
1 | = ADR 3: Use Gradle as Build Tool
2 |
3 | == Context
4 |
5 | In order to build the different components of LivingDoc 2 we need a build tool.
6 | We considered the two major Java build tools:
7 |
8 | - Maven
9 | - Gradle
10 |
11 | Maven is good for straight-forward and simple projects like libraries or
12 | microservices, because it offers a lot of structure and convention that can
13 | initially boost development speed. Experience has taught us that Maven reaches
14 | its limit with more complex projects, which require a customized build.
15 | Customization in Maven means plugin development.
16 |
17 | Gradle on the other hand is an internal DSL, which gives us the option to fall
18 | back on Groovy to _program_ a build.
19 |
20 | LivingDoc is a complex project and we expect to profit from build customization
21 | fairly early during LD2 development.
22 |
23 |
24 | == Decision
25 |
26 | We will use Gradle from the outset.
27 |
28 |
29 | == Status
30 |
31 | Accepted.
32 |
33 |
34 | == Consequences
35 |
36 | * We can gradually move from a simple initial build to a more involved build
37 | process.
38 | * Developers have to be familiar with Gradle and, for customizing the build,
39 | with Groovy.
40 |
--------------------------------------------------------------------------------
/doc/decisions/adr-004-implement-junit5-engine.adoc:
--------------------------------------------------------------------------------
1 | = ADR 4: Implement JUnit 5 Test Engine
2 |
3 | == Context
4 |
5 | In LivingDoc Legacy we had multiple plugins which provided execution of documents
6 | for different contexts:
7 |
8 | - Eclipse
9 | - IntelliJ
10 | - Maven
11 | - Gradle
12 |
13 | Each of which needed to be maintained. Having just one way of executing documents,
14 | which works for all of these contexts, would save us a lot of maintenance work.
15 |
16 | With the development of JUnit 5 there is a way of implementing generic _test engines_
17 | which are used by the _JUnit Platform_ to execute all kinds of custom tests. The
18 | platform is integrated in all of the popular IDEs and build tools.
19 |
20 | We will implement a JUnit 5 _test engine_ for the execution of LivingDoc documents.
21 | This test engine will be the bridge between the _JUnit Platform_ and LivingDoc.
22 |
23 |
24 | == Decision
25 |
26 | We will implement a JUnit 5 test engine.
27 |
28 |
29 | == Status
30 |
31 | Accepted.
32 |
33 |
34 | == Consequences
35 |
36 | * We'll have to maintain only one integration module.
37 | * We don't need to handle the integration into IDEs or build tools
38 | * We won't provide UIs for the IDEs like we did in LivingDoc Legacy
39 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 |
2 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LivingDoc/livingdoc/f3d52b8bacbdf81905e4b4a753d75f584329b297/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.4-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/livingdoc-api/livingdoc-api.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `java-project-config`
3 | }
4 |
5 | dependencies {
6 | compileOnly("org.junit.platform:junit-platform-commons:${Versions.junitPlatform}")
7 | }
8 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/After.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api;
2 |
3 | import org.livingdoc.api.documents.ExecutableDocument;
4 | import org.livingdoc.api.fixtures.scenarios.ScenarioFixture;
5 | import org.livingdoc.api.fixtures.scenarios.Step;
6 |
7 | import java.lang.annotation.ElementType;
8 | import java.lang.annotation.Retention;
9 | import java.lang.annotation.RetentionPolicy;
10 | import java.lang.annotation.Target;
11 |
12 |
13 | /**
14 | * Methods annotated with this annotation are invoked after the last fixture of an {@link ExecutableDocument} or the
15 | * last scenario {@link Step} method was invoked.
16 | *
17 | * Constraints:
18 | *
19 | * - The annotated method must not have any parameters!
20 | * - If multiple methods of a single fixture are annotated the invocation order is non-deterministic!
21 | *
22 | *
23 | * @see ExecutableDocument
24 | * @see Step
25 | * @see ScenarioFixture
26 | * @since 2.0
27 | */
28 | @Target(ElementType.METHOD)
29 | @Retention(RetentionPolicy.RUNTIME)
30 | public @interface After {
31 | }
32 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/Before.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api;
2 |
3 | import org.livingdoc.api.documents.ExecutableDocument;
4 | import org.livingdoc.api.fixtures.scenarios.ScenarioFixture;
5 | import org.livingdoc.api.fixtures.scenarios.Step;
6 |
7 | import java.lang.annotation.ElementType;
8 | import java.lang.annotation.Retention;
9 | import java.lang.annotation.RetentionPolicy;
10 | import java.lang.annotation.Target;
11 |
12 |
13 | /**
14 | * Methods annotated with this annotation are invoked before the first fixture of an {@link ExecutableDocument} or
15 | * before the first scenario {@link Step} method is invoked.
16 | *
17 | * Constraints:
18 | *
19 | * - The annotated method must not have any parameters!
20 | * - If multiple methods of a single fixture are annotated the invocation order is non-deterministic!
21 | *
22 | *
23 | * @see ExecutableDocument
24 | * @see Step
25 | * @see ScenarioFixture
26 | * @since 2.0
27 | */
28 | @Target(ElementType.METHOD)
29 | @Retention(RetentionPolicy.RUNTIME)
30 | public @interface Before {
31 | }
32 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/conversion/ConversionException.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.conversion;
2 |
3 | /**
4 | * This exception type (or one of its sub-classes) is thrown in cases where a {@link TypeConverter} could not convert a
5 | * value given to it. Since this generally means the value was 'wrong', this exception should be treated as a terminal
6 | * condition for the current test case.
7 | *
8 | * @since 2.0
9 | */
10 | public class ConversionException extends RuntimeException {
11 | /**
12 | * This Constructor takes the provided message and handles it like the RuntimeException
13 | * @param message the exception message
14 | */
15 | public ConversionException(String message) {
16 | super(message);
17 | }
18 |
19 | /**
20 | * This Constructor takes the provided message cause and handles it like the RuntimeException
21 | * @param message the exception message
22 | * @param cause the cause
23 | */
24 | public ConversionException(String message, Throwable cause) {
25 | super(message, cause);
26 | }
27 |
28 | /**
29 | * This Constructor takes the provided cause and handles it like the RuntimeException
30 | * @param cause the cause
31 | */
32 | public ConversionException(Throwable cause) {
33 | super(cause);
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/conversion/Format.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.conversion;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 |
9 | /**
10 | * Defines a format to be interpreted and used by a {@link TypeConverter}. The syntax of that format depends on the {@link
11 | * TypeConverter}. Generally these formats tend to be regular expressions or date formats. For details you'll have to take a
12 | * look at the used {@link TypeConverter}'s documentation.
13 | *
14 | * @since 2.0
15 | */
16 | @Retention(RetentionPolicy.RUNTIME)
17 | @Target({ ElementType.FIELD, ElementType.PARAMETER })
18 | public @interface Format {
19 | String value();
20 | }
21 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/conversion/Language.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.conversion;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 |
9 | /**
10 | * Overrides the used language ({@link java.util.Locale}) for the annotated field or parameter.
11 | * A full list of {@link TypeConverter} considering this annotation can be found in the documentation.
12 | * The {@link #value()} has to be specified according to the BCP 47
13 | * standard.
14 | *
15 | * Examples for this are: {@code de}, {@code de-DE}, {@code en-US} etc.
16 | *
17 | * @see java.util.Locale#forLanguageTag(String)
18 | * @since 2.0
19 | */
20 | @Retention(RetentionPolicy.RUNTIME)
21 | @Target({ ElementType.FIELD, ElementType.PARAMETER })
22 | public @interface Language {
23 | String value();
24 | }
25 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/disabled/Disabled.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.disabled;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 | /**
9 | * Disabled is used to signal that the annotated test class is currently disabled and should not be
10 | * executed.
11 | */
12 | @Target(ElementType.TYPE)
13 | @Retention(RetentionPolicy.RUNTIME)
14 | public @interface Disabled {
15 |
16 | String value() default "";
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/documents/FailFast.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.documents;
2 |
3 |
4 | import java.lang.annotation.*;
5 |
6 | /**
7 | * This annotation is used to mark a document to use fail fast behaviour. Whenever a test fails, the whole execution
8 | * should stop.
9 | */
10 | @Target(ElementType.TYPE)
11 | @Retention(RetentionPolicy.RUNTIME)
12 | public @interface FailFast {
13 | /**
14 | * The Array of Exceptions that should lead to a fast fail
15 | */
16 | Class extends Throwable>[] onExceptionTypes() default Throwable.class;
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/documents/Group.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.documents;
2 |
3 | import org.junit.platform.commons.annotation.Testable;
4 | import org.livingdoc.api.After;
5 | import org.livingdoc.api.Before;
6 |
7 | import java.lang.annotation.ElementType;
8 | import java.lang.annotation.Retention;
9 | import java.lang.annotation.RetentionPolicy;
10 | import java.lang.annotation.Target;
11 |
12 | /**
13 | * A Group contains a number of {@link ExecutableDocument ExecutableDocuments}, which are executed together.
14 | *
15 | * The execution of different Groups is guaranteed to happen in sequence.
16 | *
17 | * A Group can also define {@link Before} and {@link After} hooks, which are run before or after all documents.
18 | *
19 | * @see ExecutableDocument
20 | * @see Before
21 | * @see After
22 | */
23 | @Testable
24 | @Target(ElementType.TYPE)
25 | @Retention(RetentionPolicy.RUNTIME)
26 | public @interface Group {
27 | }
28 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/exception/ExampleSyntax.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.exception;
2 |
3 | /**
4 | * The syntax used by the business experts in the examples.
5 | */
6 | public class ExampleSyntax {
7 | /**
8 | * The string that the business expert defines in the Example to indicate
9 | * an exception is expected to be thrown.
10 | */
11 | public static final String EXCEPTION = "error";
12 | }
13 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/fixtures/decisiontables/AfterRow.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.fixtures.decisiontables;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 |
9 | /**
10 | * Methods annotated with this annotation are invoked once for each row of the decision table example just after it was
11 | * evaluated. These methods are intended to close resources initialized in {@link BeforeRow} annotated methods.
12 | *
13 | * Constraints:
14 | *
15 | * - The annotated method must not have any parameters!
16 | * - If multiple methods of a single fixture are annotated the invocation order is non-deterministic!
17 | *
18 | *
19 | * @see DecisionTableFixture
20 | * @since 2.0
21 | */
22 | @Target(ElementType.METHOD)
23 | @Retention(RetentionPolicy.RUNTIME)
24 | public @interface AfterRow {
25 | }
26 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/fixtures/decisiontables/BeforeFirstCheck.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.fixtures.decisiontables;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 |
9 | /**
10 | * Methods annotated with this annotation are always invoked before the first {@link Check} of each row is executed.
11 | * These methods are generally used to execute test code based on the {@link Input} values and store the results to be
12 | * evaluated by the {@link Check} methods. This is a purely optional mechanic! Depending on the test case, directly
13 | * executing that logic inside a {@link Check} method might be the best approach.
14 | *
15 | * Constraints:
16 | *
17 | * - The annotated method must not have any parameters!
18 | * - If multiple methods of a single fixture are annotated the invocation order is non-deterministic!
19 | *
20 | *
21 | * @see DecisionTableFixture
22 | * @see Check
23 | * @since 2.0
24 | */
25 | @Target(ElementType.METHOD)
26 | @Retention(RetentionPolicy.RUNTIME)
27 | public @interface BeforeFirstCheck {
28 | }
29 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/fixtures/decisiontables/BeforeRow.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.fixtures.decisiontables;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 |
9 | /**
10 | * Methods annotated with this annotation are invoked once for each row of the decision table example just before it is
11 | * evaluated. These methods are intended to setup resources needed for the execution of a single row.
12 | *
13 | * Constraints:
14 | *
15 | * - The annotated method must not have any parameters!
16 | * - If multiple methods of a single fixture are annotated the invocation order is non-deterministic!
17 | *
18 | *
19 | * @see DecisionTableFixture
20 | * @since 2.0
21 | */
22 | @Target(ElementType.METHOD)
23 | @Retention(RetentionPolicy.RUNTIME)
24 | public @interface BeforeRow {
25 | }
26 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/fixtures/scenarios/Binding.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.fixtures.scenarios;
2 |
3 | import java.lang.annotation.ElementType;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 | import java.lang.annotation.Target;
7 |
8 |
9 | /**
10 | * Binds a name to the annotated parameter. If the bound name occurs as parameter in a {@link Step}
11 | * annotation of this method, the extracted value will be converted and passed to this method during
12 | * execution.
13 | *
14 | * @see Step
15 | * @see ScenarioFixture
16 | * @since 2.0
17 | */
18 | @Target(ElementType.PARAMETER)
19 | @Retention(RetentionPolicy.RUNTIME)
20 | public @interface Binding {
21 | String value();
22 | }
23 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/fixtures/scenarios/ScenarioFixture.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.fixtures.scenarios;
2 |
3 | import org.livingdoc.api.After;
4 | import org.livingdoc.api.Before;
5 |
6 | import java.lang.annotation.ElementType;
7 | import java.lang.annotation.Repeatable;
8 | import java.lang.annotation.Retention;
9 | import java.lang.annotation.RetentionPolicy;
10 | import java.lang.annotation.Target;
11 |
12 |
13 | /**
14 | * Annotating a class with this annotation declares it to be a fixture for a scenario example.
15 | *
16 | * Scenario: An example describing a single test case as a sequence of steps. Each step is represented as a
17 | * sentence containing either one or more test inputs or one or more expectations.
18 | *
19 | * LivingDoc will evaluate the fixture class for consistency when it is first loaded. Only scenario related annotations can
20 | * be used within a scenario fixture!
21 | *
22 | * @see Before
23 | * @see After
24 | * @see Step
25 | * @since 2.0
26 | */
27 | @Repeatable(ScenarioFixture.ScenarioFixtures.class)
28 | @Target(ElementType.TYPE)
29 | @Retention(RetentionPolicy.RUNTIME)
30 | public @interface ScenarioFixture {
31 |
32 | String[] value();
33 |
34 | @Target(ElementType.TYPE)
35 | @Retention(RetentionPolicy.RUNTIME)
36 | @interface ScenarioFixtures {
37 | ScenarioFixture[] value();
38 | }
39 |
40 | }
41 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/tagging/Tag.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.tagging;
2 |
3 |
4 | import java.lang.annotation.*;
5 |
6 | /**
7 | * This annotation is used to specify a tag for a test, e.g. to categorize tests by environment, topic or other things.
8 | */
9 | @Target(ElementType.TYPE)
10 | @Retention(RetentionPolicy.RUNTIME)
11 | @Repeatable(Tags.class)
12 | public @interface Tag {
13 | /**
14 | * The tag as a String
15 | */
16 | String value();
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/livingdoc-api/src/main/java/org/livingdoc/api/tagging/Tags.java:
--------------------------------------------------------------------------------
1 | package org.livingdoc.api.tagging;
2 |
3 |
4 | import java.lang.annotation.*;
5 |
6 | /**
7 | * This annotation is used to specify an array of tags for a test, e.g. to categorize tests by environment, topic or
8 | * other things.
9 | */
10 | @Target(ElementType.TYPE)
11 | @Retention(RetentionPolicy.RUNTIME)
12 | public @interface Tags {
13 | /**
14 | * The tag as a String
15 | */
16 | Tag[] value();
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/livingdoc-config/livingdoc-config.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-project-config`
3 | }
4 |
5 | dependencies {
6 | implementation("org.yaml:snakeyaml:${Versions.snakeyaml}")
7 | implementation(kotlin("reflect", Versions.kotlinVersion))
8 |
9 | testCompile("org.assertj:assertj-core:${Versions.assertJ}")
10 | }
11 |
--------------------------------------------------------------------------------
/livingdoc-config/src/test/resources/test-config.yaml:
--------------------------------------------------------------------------------
1 | list:
2 | - name: bla
3 | value: 1
4 | - name: foo
5 | value: 0
6 | object:
7 | a:
8 | b:
9 | - "string"
10 | -
11 | fail:
12 | test1:
13 | test2:
--------------------------------------------------------------------------------
/livingdoc-converters/livingdoc-converters.gradle.kts:
--------------------------------------------------------------------------------
1 | plugins {
2 | `kotlin-project-config`
3 | }
4 |
5 | dependencies {
6 | implementation("org.slf4j:slf4j-api:${Versions.slf4j}")
7 | implementation(kotlin("reflect", Versions.kotlinVersion))
8 | implementation(project(":livingdoc-api"))
9 | implementation("com.beust:klaxon:${Versions.klaxon}")
10 |
11 | testCompile("ch.qos.logback:logback-classic:${Versions.logback}")
12 | testCompile("org.assertj:assertj-core:${Versions.assertJ}")
13 | }
14 |
--------------------------------------------------------------------------------
/livingdoc-converters/src/main/kotlin/org/livingdoc/converters/CharacterConverter.kt:
--------------------------------------------------------------------------------
1 | package org.livingdoc.converters
2 |
3 | import java.lang.reflect.AnnotatedElement
4 | import org.livingdoc.api.conversion.ConversionException
5 | import org.livingdoc.api.conversion.TypeConverter
6 |
7 | /**
8 | * This converter is used to convert a String with a length of 1 to a char
9 | */
10 | open class CharacterConverter : TypeConverter {
11 |
12 | /**
13 | * This function converts the given parameter value with a length of 1 to a char. If the length of value is not 1,
14 | * this function throws a Conversion exception.
15 | *
16 | * @param value the String that should have a length of 1
17 | * @return the char value of the given String
18 | * @throws ConversionException if the length is not 1
19 | */
20 | override fun convert(value: String, element: AnnotatedElement?, documentClass: Class<*>?): Char {
21 | if (value.length != 1) {
22 | throw ConversionException("not a char value: '$value'")
23 | }
24 | return value[0]
25 | }
26 |
27 | override fun canConvertTo(targetType: Class<*>): Boolean {
28 | val isJavaObjectType = Char::class.javaObjectType == targetType
29 | val isKotlinType = Char::class.java == targetType
30 | return isJavaObjectType || isKotlinType
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/livingdoc-converters/src/main/kotlin/org/livingdoc/converters/StringConverter.kt:
--------------------------------------------------------------------------------
1 | package org.livingdoc.converters
2 |
3 | import java.lang.reflect.AnnotatedElement
4 | import org.livingdoc.api.conversion.TypeConverter
5 |
6 | /**
7 | * This converter is used to convert a String to a String
8 | */
9 | open class StringConverter : TypeConverter {
10 |
11 | /**
12 | * This method 'converts' the given value to a String by returning the input string.
13 | * @param value: the input String
14 | * @return the result of the conversion as a String
15 | */
16 | override fun convert(value: String, element: AnnotatedElement?, documentClass: Class<*>?): String = value
17 |
18 | /**
19 | * This method returns true, if the parameter targetType is the java String class.
20 | */
21 | override fun canConvertTo(targetType: Class<*>) = String::class.java == targetType
22 | }
23 |
--------------------------------------------------------------------------------
/livingdoc-converters/src/main/kotlin/org/livingdoc/converters/collection/AbstractCollectionConverter.kt:
--------------------------------------------------------------------------------
1 | package org.livingdoc.converters.collection
2 |
3 | import java.lang.reflect.AnnotatedElement
4 | import org.livingdoc.api.conversion.ConversionException
5 | import org.livingdoc.api.conversion.TypeConverter
6 | import org.livingdoc.converters.TypeConverters.findTypeConverterForGenericElement
7 | import org.livingdoc.converters.collection.Tokenizer.tokenizeToStringList
8 |
9 | abstract class AbstractCollectionConverter> : TypeConverter {
10 |
11 | private val firstParameter = 0
12 |
13 | @Throws(ConversionException::class)
14 | override fun convert(value: String, element: AnnotatedElement, documentClass: Class<*>?): T {
15 | val converter = findTypeConverterForGenericElement(element, firstParameter, documentClass)
16 | val convertedValues = tokenizeToStringList(value)
17 | .map { converter.convert(it, element, documentClass) }
18 | return convertToTarget(convertedValues)
19 | }
20 |
21 | abstract fun convertToTarget(collection: List): T
22 | }
23 |
--------------------------------------------------------------------------------
/livingdoc-converters/src/main/kotlin/org/livingdoc/converters/collection/ListConverter.kt:
--------------------------------------------------------------------------------
1 | package org.livingdoc.converters.collection
2 |
3 | open class ListConverter : AbstractCollectionConverter>() {
4 |
5 | override fun convertToTarget(collection: List): List {
6 | return collection
7 | }
8 |
9 | override fun canConvertTo(targetType: Class<*>?) = List::class.java == targetType
10 | }
11 |
--------------------------------------------------------------------------------
/livingdoc-converters/src/main/kotlin/org/livingdoc/converters/collection/MapConverter.kt:
--------------------------------------------------------------------------------
1 | package org.livingdoc.converters.collection
2 |
3 | import java.lang.reflect.AnnotatedElement
4 | import org.livingdoc.api.conversion.ConversionException
5 | import org.livingdoc.api.conversion.TypeConverter
6 | import org.livingdoc.converters.TypeConverters.findTypeConverterForGenericElement
7 | import org.livingdoc.converters.collection.Tokenizer.tokenizeToMap
8 |
9 | open class MapConverter : TypeConverter