diff --git a/README.md b/README.md index f6a455d..e34f5a5 100644 --- a/README.md +++ b/README.md @@ -130,7 +130,7 @@ Those interface will be bound to one specific backing bean. A backing bean can b Methods defined in those interfaces are only allowed to return other fluent api interfaces, except for closing commands. All method parameters and methods that close a backing bean creation must be annotated with the _FluentApiBackingBeanField_ annotation which defines which value should be written. -Of course parameter and value type must match. +Of course parameter and value type must match or a correct converter must be used. Default methods will completely be ignored by the processor and can be used to transform parameters and to delegate calls to another interface method. @@ -286,12 +286,92 @@ CuteFluentApiStarter.unitTest() .expectCompilerMessage().asError().thatContains("DEF") .executeTest(); ``` + +## Advanced Techniques + +### Inline Backing Bean Mappings +Sometimes you have smaller backing beans which you might want to declare inline by using multiple parameters of the fluent api method. +The fluent api generator provides you the possibility to do that. +You have to add the _FluentApiInlineBackingBeanMapping_ annotation to the method and set the target of the corresponding _FluentApiBackingBeanMapping_ to INLINE. + +```java +@FluentApiInterface(value = MyBackingBean.class) +public interface MyFluentInterface { + // Converters in backing bean mappings + @FluentApiInlineBackingBeanMapping("nameOfTargetBackingBeanField") + MyFluentInterface doSomething( + @FluentApiBackingBeanMapping(value = "value1", target=TargetBackingBean.INLINE) Long value1, + @FluentApiBackingBeanMapping(value = "value2", target=TargetBackingBean.INLINE) Long value2 + ); + +} +``` +In this example an inline backing bean will be set at _MyBackingBean.nameOfTargetBackingBeanField_. +It's _value1_ and _value2_ attributes will be mapped from the corresponding method parameters. + +### Converters +Converters can be used to map input parameters from either implicit value annotations or backing bean mappings to the backing bean type. + +An example Converter: +```java +public static class TargetType { + + private final String value; + + public TargetType (String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } +} + +public static class MyStringConverter implements FluentApiConverter { + + @Override + public TargetType convert(String o) { + return new TargetType(o); + } + +} + +public static class MyLongConverter implements FluentApiConverter { + + @Override + public TargetType convert(Long o) { + // not null save ;) + return new TargetType(o.toString()); + } + +} + +@FluentApiInterface(value = MyBackingBean.class) +public interface MyFluentInterface { + + // Converters in implicit value annotation + @FluentApiImplicitValue(id = "singleValue", value = "SINGLE", converter = MyStringConverter.class) + MyFluentInterface setSingleValue(); + + // Converters in backing bean mappings + MyFluentInterface setViaLongValue(@FluentApiBackingBeanMapping(value = "singleValue", converter = MyLongConverter.class) Long longValue); + +} +``` + +### Javas default methods in fluent api and backing bean in interfaces +Default methods will be ignored during processing of fluent api and backing bean interfaces and can be used for different tasks: + +- They can provide alternative ways to set a parameter by providing conversions of input parameters and internally calling fluent api methods. +- They can also be very helpful to provide methods for accessing/filtering/aggregate backing bean attributes. + # Contributing We welcome any kind of suggestions and pull requests. -## Building and developing the ${rootArtifactId} annotation processor +## Building and developing the FluApiGen annotation processor This project is built using Maven. A simple import of the pom in your IDE should get you up and running. To build the project on the commandline, just run `./mvnw` or `./mvnw clean install` diff --git a/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiBackingBeanMapping.java b/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiBackingBeanMapping.java index 30d80e0..d366cf0 100644 --- a/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiBackingBeanMapping.java +++ b/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiBackingBeanMapping.java @@ -25,7 +25,7 @@ * Defines the target backing bean to set the value for. * This can be either the current backing bean defined via the {@link FluentApiInterface} annotation or the next backing bean defined by the methods return value. * In this case the return value must correspond to an interface annotated with the {@link FluentApiInterface}. - * @return The targetted backing bean, defaults to THIS (== the current backing bean) + * @return The targeted backing bean, defaults to THIS (== the current backing bean) */ TargetBackingBean target() default TargetBackingBean.THIS; @@ -37,4 +37,10 @@ */ MappingAction action() default MappingAction.SET; + /** + * Converter to use for non-matching fluent interface parameter types. + * @return the converted value. + */ + Class converter () default FluentApiConverter.NoConversion.class; + } diff --git a/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiConverter.java b/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiConverter.java new file mode 100644 index 0000000..bc7f96f --- /dev/null +++ b/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiConverter.java @@ -0,0 +1,20 @@ +package io.toolisticon.fluapigen.api; + +/** + * Simple converter interface for fluent api parameters, + * + * @param The source type + * @param The target type + */ +public interface FluentApiConverter { + TARGET convert(SOURCE source); + + + class NoConversion implements FluentApiConverter { + @Override + public TYPE convert(TYPE type) { + return type; + } + } + +} diff --git a/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiImplicitValue.java b/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiImplicitValue.java index a29ef25..31a6a5f 100644 --- a/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiImplicitValue.java +++ b/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiImplicitValue.java @@ -39,4 +39,10 @@ MappingAction action() default MappingAction.SET; + /** + * Converter to use for non matching fluent interface parameter types. + * @return the converted value. + */ + Class converter () default FluentApiConverter.NoConversion.class; + } diff --git a/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiInlineBackingBeanMapping.java b/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiInlineBackingBeanMapping.java index 3968c40..40aa556 100644 --- a/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiInlineBackingBeanMapping.java +++ b/fluapigen-api/src/main/java/io/toolisticon/fluapigen/api/FluentApiInlineBackingBeanMapping.java @@ -2,7 +2,6 @@ import java.lang.annotation.Documented; import java.lang.annotation.ElementType; -import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; diff --git a/fluapigen-integrationTest/pom.xml b/fluapigen-integrationTest/pom.xml index bab0684..9f3603c 100644 --- a/fluapigen-integrationTest/pom.xml +++ b/fluapigen-integrationTest/pom.xml @@ -100,7 +100,7 @@ io.toolisticon.cute cute - compile + test diff --git a/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/CuteFluentApi.java b/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/CuteFluentApi.java deleted file mode 100644 index 2e34cf4..0000000 --- a/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/CuteFluentApi.java +++ /dev/null @@ -1,389 +0,0 @@ -package io.toolisticon.cute; - - -import io.toolisticon.fluapigen.api.FluentApi; -import io.toolisticon.fluapigen.api.FluentApiBackingBean; -import io.toolisticon.fluapigen.api.FluentApiBackingBeanField; -import io.toolisticon.fluapigen.api.FluentApiBackingBeanMapping; -import io.toolisticon.fluapigen.api.FluentApiCommand; -import io.toolisticon.fluapigen.api.FluentApiImplicitValue; -import io.toolisticon.fluapigen.api.FluentApiInterface; -import io.toolisticon.fluapigen.api.FluentApiParentBackingBeanMapping; -import io.toolisticon.fluapigen.api.FluentApiRoot; -import io.toolisticon.fluapigen.api.MappingAction; -import io.toolisticon.fluapigen.api.TargetBackingBean; - -import javax.annotation.processing.Processor; -import javax.lang.model.element.Element; -import javax.tools.FileObject; -import javax.tools.JavaFileManager; -import javax.tools.JavaFileObject; -import javax.tools.StandardLocation; -import java.lang.annotation.Annotation; -import java.util.List; -import java.util.Locale; - -@FluentApi("CuteFluentApiStarter") -public class CuteFluentApi { - - @FluentApiBackingBean - public interface CompilerTestBB { - - @FluentApiBackingBeanField("testType") - String getTestType(); - - - - @FluentApiBackingBeanField("compilationSucceeded") - Boolean compilationSucceeded(); - - @FluentApiBackingBeanField("exceptionIsThrown") - Class getExceptionIsThrown(); - - @FluentApiBackingBeanField("compileMessageChecks") - List compilerMessageChecks(); - - @FluentApiBackingBeanField("javaFileObjectChecks") - List javaFileObjectChecks(); - - @FluentApiBackingBeanField("fileObjectChecks") - List fileObjectChecks(); - - } - - - @FluentApiBackingBean - public interface PassInConfigurationBB { - @FluentApiBackingBeanField("passedInClass") - Class getPassedInClass(); - - @FluentApiBackingBeanField("annotationToScanFor") - Class getAnnotationToScanFor(); - - @FluentApiBackingBeanField("passedInProcessor") - Class getPassedInProcessor(); - } - - @FluentApiBackingBean - public interface CompilerMessageCheckBB { - - @FluentApiBackingBeanField("compilerMessageScope") - CompilerMessageScope getCompilerMessageScope(); - - @FluentApiBackingBeanField("compilerMessageComparisonType") - CompilerMessageComparisonType getComparisonType(); - - @FluentApiBackingBeanField("searchString") - List getSearchString(); - - @FluentApiBackingBeanField("atLine") - Integer atLine(); - - @FluentApiBackingBeanField("atColumn") - Integer atColumn(); - - @FluentApiBackingBeanField("atSource") - String atSource(); - - @FluentApiBackingBeanField("withLocale") - Locale withLocale(); - - } - - - public enum TestType { - UNIT, - BLACK_BOX - } - - public enum CompilerMessageScope { - NOTE, - WARNING, - MANDATORY_WARNING, - ERROR; - } - - public enum CompilerMessageComparisonType { - CONTAINS, - EQUALS; - } - - - public enum FileObjectCheckType { - EXISTS, - DOESNT_EXIST - } - - @FluentApiBackingBean - public interface GeneratedJavaFileObjectCheckBB { - - @FluentApiBackingBeanField("checkType") - FileObjectCheckType getCheckType(); - - @FluentApiBackingBeanField("location") - JavaFileManager.Location getLocation(); - - @FluentApiBackingBeanField("className") - String getClassName(); - - @FluentApiBackingBeanField("kind") - JavaFileObject.Kind getKind(); - - @FluentApiBackingBeanField("generatedFileObjectMatcher") - GeneratedFileObjectMatcher getGeneratedFileObjectMatcher(); - } - - @FluentApiBackingBean - public interface GeneratedFileObjectCheckBB { - - @FluentApiBackingBeanField("checkType") - FileObjectCheckType getCheckType(); - - @FluentApiBackingBeanField("location") - JavaFileManager.Location getLocation(); - - @FluentApiBackingBeanField("packageName") - String getPackageName(); - - @FluentApiBackingBeanField("relativeName") - String getRelativeName(); - - @FluentApiBackingBeanField("generatedFileObjectMatcher") - GeneratedFileObjectMatcher[] getGeneratedFileObjectMatchers(); - } - - - @FluentApiInterface(CompilerTestBB.class) - @FluentApiRoot - public interface MyRootInterface { - - @FluentApiImplicitValue(id = "testType", value = "UNIT") - CompilerTestInterface unitTest(); - - - @FluentApiImplicitValue(id = "testType", value = "BLACK_BOX") - CompilerTestInterface blackBoxTest(); - - - } - - @FluentApiInterface(CompilerTestBB.class) - public interface UnitTestRootInterface { - - - CompilerTestInterface when(); - - } - - @FluentApiInterface(CompilerTestBB.class) - public interface UnitTestGivenInterface { - - UnitTestWhenInterface when(); - - } - - @FluentApiInterface(PassInConfigurationBB.class) - public interface UnitTestWhenInterface { - - default UnitTestWhenWithPassedInElementInterface passInElement(Class classToScan){ - return this.passInElement(classToScan, PassIn.class); - } - - UnitTestWhenWithPassedInElementInterface passInElement(@FluentApiBackingBeanMapping(value = "passedInClass") Class classToScan, @FluentApiBackingBeanMapping(value = "annotationToScanFor") Class annotationToSearch); - -

UnitTestWhenWithPassedInProcessorInterface

passInProcessor(@FluentApiBackingBeanMapping(value = "passedInProcessor")Class

processor); - - default UnitTestWhenWithPassedInElementAndProcessorInterface passInElementAndProcessor(Class classToScanForElement, Class

processor){ - return this.passInElementAndProcessor(classToScanForElement, PassIn.class, processor); - } - - UnitTestWhenWithPassedInElementAndProcessorInterface passInElementAndProcessor(@FluentApiBackingBeanMapping(value = "passedInClass")Class classToScanForElement, @FluentApiBackingBeanMapping(value = "annotationToScanFor") Class annotationToSearch, @FluentApiBackingBeanMapping(value = "passedInProcessor")Class

processor); - - - } - - @FluentApiInterface(CompilerTestBB.class) - public interface UnitTestWhenWithPassedInElementInterface { - //CompilerTestInterface into (@FluentApiBackingBeanMapping() UnitTestAnnotationProcessorClassWithPassIn unitTest); - } - - @FluentApiInterface(CompilerTestBB.class) - public interface UnitTestWhenWithPassedInProcessorInterface

{ - //CompilerTestInterface into (UnitTestAnnotationProcessorClassForTestingAnnotationProcessors unitTest); - } - - @FluentApiInterface(CompilerTestBB.class) - public interface UnitTestWhenWithPassedInElementAndProcessorInterface { - //CompilerTestInterface into (UnitTestAnnotationProcessorClassForTestingAnnotationProcessorsWithPassIn unitTest); - } - - @FluentApiInterface(CompilerTestBB.class) - public interface CompilerTestInterface { - - - CompilerTestExpectThatInterface expectThat(); - - - } - - - - - - - @FluentApiInterface(CompilerTestBB.class) - public interface CompilerTestExpectAndThatInterface { - - CompilerTestExpectThatInterface andThat(); - - @FluentApiCommand(ExecuteTestCommand.class) - void executeTest(); - - } - - @FluentApiInterface(CompilerTestBB.class) - public interface CompilerTestExpectThatInterface { - - @FluentApiImplicitValue(id = "compilationSucceeded", value = "true") - CompilerTestExpectAndThatInterface compilationSucceeds(); - - @FluentApiImplicitValue(id = "compilationSucceeded", value = "false") - CompilerTestExpectAndThatInterface compilationFails(); - - - default GeneratedJavaFileObjectCheck generatedClass(String className) { - return javaFileObject(StandardLocation.CLASS_OUTPUT, className, JavaFileObject.Kind.CLASS); - } - - default GeneratedJavaFileObjectCheck generatedSourceFile(String className) { - return javaFileObject(StandardLocation.CLASS_OUTPUT, className, JavaFileObject.Kind.SOURCE); - } - - default GeneratedFileObjectCheck generatedResourceFile(String packageName, - String relativeName) { - return fileObject(StandardLocation.CLASS_OUTPUT, packageName, relativeName); - } - - GeneratedJavaFileObjectCheck javaFileObject( - @FluentApiBackingBeanMapping(value = "location", target = TargetBackingBean.NEXT) JavaFileManager.Location location, - @FluentApiBackingBeanMapping(value = "className", target = TargetBackingBean.NEXT) String className, - @FluentApiBackingBeanMapping(value = "kind", target = TargetBackingBean.NEXT) JavaFileObject.Kind kind); - - GeneratedFileObjectCheck fileObject( - @FluentApiBackingBeanMapping(value = "location", target = TargetBackingBean.NEXT) JavaFileManager.Location location, - @FluentApiBackingBeanMapping(value = "packageName", target = TargetBackingBean.NEXT) String packageName, - @FluentApiBackingBeanMapping(value = "relativeName", target = TargetBackingBean.NEXT) String relativeName); - - - CompilerTestExpectAndThatInterface exceptionIsThrown(@FluentApiBackingBeanMapping(value = "exceptionIsThrown") Class exception); - - CompilerMessageCheckMessageType compilerMessage(); - - - } - - - @FluentApiInterface(CompilerMessageCheckBB.class) - public interface CompilerMessageCheckMessageType { - - @FluentApiImplicitValue(id = "compilerMessageScope", value = "NOTE") - CompilerMessageCheckComparisonType ofKindNote(); - - @FluentApiImplicitValue(id = "compilerMessageScope", value = "WARNING") - CompilerMessageCheckComparisonType ofKindWarning(); - - @FluentApiImplicitValue(id = "compilerMessageScope", value = "MANDATORY_WARNING") - CompilerMessageCheckComparisonType ofKindMandatoryWarning(); - - @FluentApiImplicitValue(id = "compilerMessageScope", value = "ERROR") - CompilerMessageCheckComparisonType ofKindError(); - - } - - @FluentApiInterface(CompilerMessageCheckBB.class) - public interface CompilerMessageCheckComparisonType { - - @FluentApiImplicitValue(id = "compilerMessageComparisonType", value = "CONTAINS") - @FluentApiParentBackingBeanMapping(value = "compileMessageChecks") - CompilerTestExpectAndThatInterface contains( - @FluentApiBackingBeanMapping(value = "searchString", action = MappingAction.SET) String... text - ); - - - @FluentApiImplicitValue(id = "compilerMessageComparisonType", value = "EQUALS") - @FluentApiParentBackingBeanMapping(value = "compileMessageChecks") - CompilerTestExpectAndThatInterface equals( - @FluentApiBackingBeanMapping(value = "searchString", action = MappingAction.SET) String text - ); - - - CompilerMessageCheckComparisonType atLine(@FluentApiBackingBeanMapping(value = "atLine") int line); - - CompilerMessageCheckComparisonType atColumn(@FluentApiBackingBeanMapping(value = "atColumn") int column); - - CompilerMessageCheckComparisonType atSource(@FluentApiBackingBeanMapping(value = "atSource") String column); - - CompilerMessageCheckComparisonType withLocale(@FluentApiBackingBeanMapping(value = "withLocale") Locale column); - - } - - @FluentApiInterface(GeneratedJavaFileObjectCheckBB.class) - public interface GeneratedJavaFileObjectCheck { - - @FluentApiImplicitValue(id = "checkType", value = "EXISTS") - @FluentApiParentBackingBeanMapping(value = "javaFileObjectChecks", action = MappingAction.ADD) - CompilerTestExpectAndThatInterface exists(); - - @FluentApiImplicitValue(id = "checkType", value = "DOESNT_EXIST") - @FluentApiParentBackingBeanMapping(value = "javaFileObjectChecks", action = MappingAction.ADD) - CompilerTestExpectAndThatInterface doesntExist(); - - default CompilerTestExpectAndThatInterface matches(JavaFileObject expectedJavaFileObject) { - return matches(CompileTestBuilder.ExpectedFileObjectMatcherKind.BINARY, expectedJavaFileObject); - } - - default CompilerTestExpectAndThatInterface matches(CompileTestBuilder.ExpectedFileObjectMatcherKind expectedFileObjectMatcherKind, JavaFileObject expectedJavaFileObject) { - return matches(expectedFileObjectMatcherKind.createMatcher(expectedJavaFileObject)); - } - - @FluentApiParentBackingBeanMapping(value = "javaFileObjectChecks", action = MappingAction.ADD) - CompilerTestExpectAndThatInterface matches(@FluentApiBackingBeanMapping(value = "generatedFileObjectMatcher") GeneratedFileObjectMatcher generatedJavaFileObjectCheck); - - } - - @FluentApiInterface(GeneratedFileObjectCheckBB.class) - public interface GeneratedFileObjectCheck { - - @FluentApiImplicitValue(id = "checkType", value = "EXISTS") - @FluentApiParentBackingBeanMapping(value = "fileObjectChecks", action = MappingAction.ADD) - CompilerTestExpectAndThatInterface exists(); - - @FluentApiImplicitValue(id = "checkType", value = "DOESNT_EXIST") - @FluentApiParentBackingBeanMapping(value = "fileObjectChecks", action = MappingAction.ADD) - CompilerTestExpectAndThatInterface doesntExist(); - - default CompilerTestExpectAndThatInterface matches(FileObject expectedFileObject) { - return matches(CompileTestBuilder.ExpectedFileObjectMatcherKind.TEXT_IGNORE_LINE_ENDINGS, expectedFileObject); - } - - default CompilerTestExpectAndThatInterface matches(CompileTestBuilder.ExpectedFileObjectMatcherKind expectedFileObjectMatcherKind, FileObject expectedFileObject) { - return matches(expectedFileObjectMatcherKind.createMatcher(expectedFileObject)); - } - - @FluentApiParentBackingBeanMapping(value = "fileObjectChecks", action = MappingAction.ADD) - CompilerTestExpectAndThatInterface matches(@FluentApiBackingBeanMapping(value = "generatedFileObjectMatcher") GeneratedFileObjectMatcher... generatedJavaFileObjectCheck); - - - } - - - // Commands - @FluentApiCommand - public static class ExecuteTestCommand { - static void myCommand(CompilerTestBB backingBean) { - System.out.println("DONE"); - } - } - - -} \ No newline at end of file diff --git a/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/GenericsTest.java b/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/GenericsTest.java new file mode 100644 index 0000000..6f45836 --- /dev/null +++ b/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/GenericsTest.java @@ -0,0 +1,87 @@ +package io.toolisticon.cute; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiImplicitValue; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; +import io.toolisticon.fluapigen.api.MappingAction; + +import java.util.ArrayList; +import java.util.List; + +@FluentApi("InheritenceTestBuilder") +public class GenericsTest { + + + @FluentApiBackingBean + public interface MyRootBackingBean { + List values(); + + Conversion filterBy(); + } + + + enum Conversion { + STRING, + INTEGER + } + + + @FluentApiRoot + @FluentApiInterface(MyRootBackingBean.class) + public interface RootInterface { + + MyFilterInterface valuesToFilter(@FluentApiBackingBeanMapping(value = "values", action = MappingAction.SET) List values); + } + + @FluentApiInterface(MyRootBackingBean.class) + public interface MyFilterInterface { + @FluentApiImplicitValue(id = "filterBy", value = "STRING") + MyClosingInterface isString(); + + @FluentApiImplicitValue(id = "filterBy", value = "INTEGER") + MyClosingInterface isInteger(); + } + + + @FluentApiInterface(MyRootBackingBean.class) + public interface MyClosingInterface { + + @FluentApiCommand(ClosingCommand.class) + List close(); + + } + + + @FluentApiCommand + public static class ClosingCommand { + static List myCommand(GenericsTest.MyRootBackingBean backingBean) { + List result = new ArrayList<>(); + + for (Object value : backingBean.values()) { + switch (backingBean.filterBy()) { + case STRING: { + if (value instanceof String) { + result.add((T) value); + } + break; + } + case INTEGER: { + if (value instanceof Integer) { + result.add((T) value); + } + break; + } + default: { + result.add((T) value); + } + } + } + + return (List) result; + } + } +} diff --git a/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/ImplicitValueConverterTest.java b/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/ImplicitValueConverterTest.java new file mode 100644 index 0000000..733c3ce --- /dev/null +++ b/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/ImplicitValueConverterTest.java @@ -0,0 +1,79 @@ +package io.toolisticon.cute; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import io.toolisticon.fluapigen.api.FluentApiImplicitValue; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; +import io.toolisticon.fluapigen.api.MappingAction; + +import java.util.List; + +@FluentApi("ImplicitValueConverterTestBuilder") +public class ImplicitValueConverterTest { + + public static class TargetType { + + private final String value; + + public TargetType (String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + } + + public static class MyConverter implements FluentApiConverter { + + @Override + public TargetType convert(String o) { + return new TargetType(o); + } + + } + + @FluentApiBackingBean + public interface TestBackingBean { + + TargetType singleValue(); + + List collectionValue(); + + TargetType[] arrayValue(); + + } + + @FluentApiRoot + @FluentApiInterface(value = TestBackingBean.class) + public interface MyFluentInterface{ + + @FluentApiImplicitValue(id="singleValue", value = "SINGLE", converter = MyConverter.class) + MyFluentInterface setSingleValue(); + + @FluentApiImplicitValue(id = "collectionValue", value={"ONE", "TWO", "THREE"}, action = MappingAction.SET, converter = MyConverter.class) + MyFluentInterface setCollectionValue(); + + @FluentApiImplicitValue(id = "collectionValue", value={"A", "B", "C"}, action = MappingAction.ADD, converter = MyConverter.class) + MyFluentInterface addCollectionValue(); + + @FluentApiImplicitValue(id="arrayValue", value = {"A", "B", "C"},converter = MyConverter.class) + MyFluentInterface setArrayValue(); + + @FluentApiCommand(MyCommand.class) + TestBackingBean myCommand(); + + } + + @FluentApiCommand() + public static class MyCommand { + public static TestBackingBean myCommand(TestBackingBean testBackingBean) { + return testBackingBean; + } + } + +} diff --git a/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/TestUsage.java b/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/TestUsage.java deleted file mode 100644 index 63332ba..0000000 --- a/fluapigen-integrationTest/src/main/java/io/toolisticon/cute/TestUsage.java +++ /dev/null @@ -1,27 +0,0 @@ -package io.toolisticon.cute; - - -import javax.tools.JavaFileObject; -import javax.tools.StandardLocation; - -public class TestUsage { - - public static void main(String[] args) { - CuteFluentApi.CompilerTestExpectAndThatInterface tst = CuteFluentApiStarter.unitTest() - .expectThat().exceptionIsThrown(IllegalArgumentException.class) - .andThat().javaFileObject(StandardLocation.CLASS_OUTPUT, "Wtf1", JavaFileObject.Kind.CLASS).exists() - .andThat().javaFileObject(StandardLocation.CLASS_OUTPUT, "Wtf2", JavaFileObject.Kind.CLASS).exists() - .andThat().generatedClass("Wtf3").exists() - .andThat().compilationSucceeds() - .andThat().compilerMessage().ofKindError().atLine(10).atColumn(5).contains("WTF") - .andThat().compilerMessage().ofKindError().atLine(11).contains("WTF2"); - - - tst.executeTest(); - System.out.println(""); - - CompileTestBuilder.unitTest(); - - } - -} diff --git a/fluapigen-integrationTest/src/test/java/io/toolisticon/fluapigen/integrationtest/GenericsTestTest.java b/fluapigen-integrationTest/src/test/java/io/toolisticon/fluapigen/integrationtest/GenericsTestTest.java new file mode 100644 index 0000000..76ec4cf --- /dev/null +++ b/fluapigen-integrationTest/src/test/java/io/toolisticon/fluapigen/integrationtest/GenericsTestTest.java @@ -0,0 +1,20 @@ +package io.toolisticon.fluapigen.integrationtest; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import io.toolisticon.cute.InheritenceTestBuilder; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +public class GenericsTestTest { + + @Test + public void testFiltering(){ + + MatcherAssert.assertThat(InheritenceTestBuilder.valuesToFilter(Arrays.asList("abc",1,3,5,"def")).isInteger().close(), Matchers.contains(1,3,5)); + MatcherAssert.assertThat(InheritenceTestBuilder.valuesToFilter(Arrays.asList("abc",1,3,5,"def")).isString().close(), Matchers.contains("abc", "def")); + + } +} diff --git a/fluapigen-integrationTest/src/test/java/io/toolisticon/fluapigen/integrationtest/ImplicitValueConverterTestTest.java b/fluapigen-integrationTest/src/test/java/io/toolisticon/fluapigen/integrationtest/ImplicitValueConverterTestTest.java new file mode 100644 index 0000000..5524349 --- /dev/null +++ b/fluapigen-integrationTest/src/test/java/io/toolisticon/fluapigen/integrationtest/ImplicitValueConverterTestTest.java @@ -0,0 +1,32 @@ +package io.toolisticon.fluapigen.integrationtest; + +import io.toolisticon.cute.ImplicitValueConverterTest; +import io.toolisticon.cute.ImplicitValueConverterTestBuilder; +import org.hamcrest.MatcherAssert; +import org.hamcrest.Matchers; +import org.junit.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.stream.Collectors; + +public class ImplicitValueConverterTestTest { + + @Test + public void test() { + + ImplicitValueConverterTest.TestBackingBean testBackingBean = ImplicitValueConverterTestBuilder.setSingleValue() + .setCollectionValue() + .addCollectionValue() + .setArrayValue() + .myCommand(); + + MatcherAssert.assertThat(testBackingBean.collectionValue().stream().map(e -> e.toString()).collect(Collectors.toList()), Matchers.contains("ONE", "TWO", "THREE", "A", "B", "C")); + MatcherAssert.assertThat(Arrays.asList(testBackingBean.arrayValue()).stream().map(e -> e.toString()).collect(Collectors.toList()), Matchers.contains( "A", "B", "C")); + MatcherAssert.assertThat(testBackingBean.singleValue().toString(), Matchers.is( "SINGLE")); + + + + } + +} diff --git a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/CompilerErrorException.java b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/CompilerErrorException.java new file mode 100644 index 0000000..d88fcc2 --- /dev/null +++ b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/CompilerErrorException.java @@ -0,0 +1,5 @@ +package io.toolisticon.fluapigen.processor; + +public abstract class CompilerErrorException extends RuntimeException{ + public abstract void writeErrorCompilerMessage(); +} diff --git a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/IncompatibleConverterException.java b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/IncompatibleConverterException.java new file mode 100644 index 0000000..2e4dc14 --- /dev/null +++ b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/IncompatibleConverterException.java @@ -0,0 +1,32 @@ +package io.toolisticon.fluapigen.processor; + +import io.toolisticon.aptk.compilermessage.api.DeclareCompilerMessage; +import io.toolisticon.aptk.tools.TypeMirrorWrapper; + +import java.util.List; + +@DeclareCompilerMessage(code = "603", enumValueName = "BB_MAPPING_INVALID_CONVERTER", message = "The source and or target type of the configured converter ${4} must be <${0},${1}> but are <${2},${3}>", processorClass = FluentApiProcessor.class) + +public class IncompatibleConverterException extends CompilerErrorException{ + + final FluentApiBackingBeanMappingWrapper annotation; + final TypeMirrorWrapper sourceType; + final TypeMirrorWrapper targetType; + + final TypeMirrorWrapper converterType; + + final List converterTypeArguments; + + public IncompatibleConverterException(FluentApiBackingBeanMappingWrapper annotation,TypeMirrorWrapper sourceType, TypeMirrorWrapper targetType, TypeMirrorWrapper converterType, List converterTypeArguments) { + this.annotation = annotation; + this.sourceType = sourceType; + this.targetType = targetType; + this.converterType = converterType; + this.converterTypeArguments = converterTypeArguments; + } + + @Override + public void writeErrorCompilerMessage() { + annotation.converterAsAttributeWrapper().compilerMessage().asError().write(FluentApiProcessorCompilerMessages.BB_MAPPING_INVALID_CONVERTER,converterTypeArguments.get(0),converterTypeArguments.get(1), sourceType, targetType, converterType.getSimpleName()); + } +} diff --git a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/IncompatibleParameterTypeException.java b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/IncompatibleParameterTypeException.java index f0507dc..826de77 100644 --- a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/IncompatibleParameterTypeException.java +++ b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/IncompatibleParameterTypeException.java @@ -9,7 +9,7 @@ import javax.lang.model.element.Element; @DeclareCompilerMessage(code = "602", enumValueName = "ERROR_INCOMPATIBLE_BACKING_BEAN_MAPPING_TYPES", message = "Cannot map parameter of type ${0} to backing bean field '${1}' with type '${2}'", processorClass = FluentApiProcessor.class) -public class IncompatibleParameterTypeException extends RuntimeException{ +public class IncompatibleParameterTypeException extends CompilerErrorException{ final String parameterType; diff --git a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterfaceImplicitValue.java b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterfaceImplicitValue.java index be9cfcc..f228ddb 100644 --- a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterfaceImplicitValue.java +++ b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterfaceImplicitValue.java @@ -1,6 +1,13 @@ package io.toolisticon.fluapigen.processor; import io.toolisticon.aptk.compilermessage.api.DeclareCompilerMessage; +import io.toolisticon.aptk.tools.InterfaceUtils; +import io.toolisticon.aptk.tools.TypeMirrorWrapper; +import io.toolisticon.fluapigen.api.FluentApiConverter; + +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; public class ModelInterfaceImplicitValue implements Validatable { @@ -19,7 +26,45 @@ public String getBackingBeanFieldName() { } public String getValueAssignmentString() { - return ModelBackingBeanField.getAssignmentString(backingBeanField.getFieldType(), annotation.value(), annotation.action()); + if (!annotation.converterIsDefaultValue()) { + if (this.backingBeanField.isCollection()) { + + switch (annotation.action()) { + + case SET: { + + if (annotation.value().length == 0) { + return " = new " + backingBeanField.getCollectionImplType() + "()"; + } else { + String valueString = Arrays.stream(annotation.value()).map(e -> "new " + annotation.converterAsFqn() + "().convert(\"" + e + "\")").collect(Collectors.joining(", ")); + return " = new " + backingBeanField.getCollectionImplType() + "(Arrays.asList(" + valueString + "))"; + } + + } + case ADD: + default: { + + if (annotation.value().length == 0) { + return ".addAll(Arrays.asList(Collections.EMPTY_LIST))"; + } else { + String valueString = Arrays.stream(annotation.value()).map(e -> "new " + annotation.converterAsFqn() + "().convert(\"" + e + "\")").collect(Collectors.joining(", ")); + return ".addAll(Arrays.asList(" + valueString + "))"; + } + + } + } + } else if (this.backingBeanField.isArray()) { + + String valueString = Arrays.stream(annotation.value()).map(e -> "new " + annotation.converterAsFqn() + "().convert(\"" + e + "\")").collect(Collectors.joining(", ")); + return " = new " + this.backingBeanField.getFieldType().getWrappedComponentType().getSimpleName() + "[]" + "{ " + valueString + " }"; + + } else { + return " = new " + annotation.converterAsFqn() + "().convert(\"" + (annotation.value())[0] + "\")"; + } + + } else { + return ModelBackingBeanField.getAssignmentString(backingBeanField.getFieldType(), annotation.value(), annotation.action()); + } } @@ -28,10 +73,33 @@ public String getValueAssignmentString() { @DeclareCompilerMessage(code = "401", enumValueName = "ERROR_IMPLICIT_VALUE_UNSUPPORTED_TYPE", message = "Target type '${0}' is not supported", processorClass = FluentApiProcessor.class) @DeclareCompilerMessage(code = "402", enumValueName = "ERROR_IMPLICIT_VALUE_INVALID_ENUM_VALUE", message = "Enum '${0}' has no value '${1}'. Must be one of ${2}", processorClass = FluentApiProcessor.class) @DeclareCompilerMessage(code = "403", enumValueName = "ERROR_IMPLICIT_VALUE_MUST_BE_SINGLE_VALUE", message = "Implicit value must be one single value", processorClass = FluentApiProcessor.class) + @DeclareCompilerMessage(code = "404", enumValueName = "ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_SOURCE_TYPE_STRING", message = "Implicit value converter must take String as source type but got ${0}", processorClass = FluentApiProcessor.class) + @DeclareCompilerMessage(code = "405", enumValueName = "ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_TO_TARGET_ATTRIBUTE_TYPE", message = "Implicit value converter must convert to target attribute type ${0} but found ${1}.", processorClass = FluentApiProcessor.class) public boolean validate() { try { + + if (!this.annotation.converterIsDefaultValue()) { + List typeParameters = InterfaceUtils.getResolvedTypeArgumentOfSuperTypeOrInterface(this.annotation.converterAsTypeMirrorWrapper().getTypeElement().get(), TypeMirrorWrapper.wrap(FluentApiConverter.class)); + // must check if converter matches source and target type + if (typeParameters.size() == 2) { + + if (!TypeMirrorWrapper.wrap(String.class).equals(typeParameters.get(0))) { + annotation.valueAsAttributeWrapper().compilerMessage().asError().write(FluentApiProcessorCompilerMessages.ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_SOURCE_TYPE_STRING, typeParameters.get(0).getSimpleName()); + } + + TypeMirrorWrapper targetType = typeParameters.get(1); + TypeMirrorWrapper targetBackingBeanFieldType = this.backingBeanField.getFieldType().isArray() || this.backingBeanField.getFieldType().isCollection() ? this.backingBeanField.getFieldType().getWrappedComponentType() : this.backingBeanField.getFieldType(); + + if (!targetType.erasure().isAssignableTo(targetBackingBeanFieldType.erasure())) { + annotation.valueAsAttributeWrapper().compilerMessage().asError().write(FluentApiProcessorCompilerMessages.ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_TO_TARGET_ATTRIBUTE_TYPE, targetBackingBeanFieldType.getSimpleName(), targetType.getSimpleName()); + } + } + + + } + getValueAssignmentString(); return true; } catch (NumberFormatException e) { diff --git a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterfaceMethodParameter.java b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterfaceMethodParameter.java index f625974..f540d35 100644 --- a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterfaceMethodParameter.java +++ b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterfaceMethodParameter.java @@ -1,11 +1,14 @@ package io.toolisticon.fluapigen.processor; import io.toolisticon.aptk.compilermessage.api.DeclareCompilerMessage; +import io.toolisticon.aptk.tools.InterfaceUtils; import io.toolisticon.aptk.tools.TypeMirrorWrapper; import io.toolisticon.aptk.tools.wrapper.VariableElementWrapper; import io.toolisticon.fluapigen.api.FluentApiBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiConverter; import io.toolisticon.fluapigen.api.TargetBackingBean; +import java.util.List; import java.util.Optional; import java.util.stream.Collectors; @@ -21,14 +24,14 @@ public class ModelInterfaceMethodParameter { final TypeMirrorWrapper type; - final FluentApiBackingBeanMapping fluentApiBackingBeanMapping; + final FluentApiBackingBeanMappingWrapper fluentApiBackingBeanMapping; ModelInterfaceMethodParameter(VariableElementWrapper variableElement, ModelBackingBean backingBeanModel, ModelInterfaceMethod modelInterfaceMethod) { parameterElement = variableElement; this.backingBeanModel = backingBeanModel; this.modelInterfaceMethod = modelInterfaceMethod; parameterName = variableElement.getSimpleName(); - fluentApiBackingBeanMapping = variableElement.unwrap().getAnnotation(FluentApiBackingBeanMapping.class); + fluentApiBackingBeanMapping = FluentApiBackingBeanMappingWrapper.wrap(variableElement.unwrap()); type = variableElement.asType(); } @@ -59,14 +62,25 @@ public Optional getBackingBeanField() { return returnValue; } - public FluentApiBackingBeanMapping getFluentApiBackingBeanMapping() { + public FluentApiBackingBeanMappingWrapper getFluentApiBackingBeanMapping() { return fluentApiBackingBeanMapping; } + public boolean hasConverter () { + return !fluentApiBackingBeanMapping.converterIsDefaultValue(); + //&& !getFluentApiBackingBeanMapping().converterAsFqn().equals(FluentApiConverter.NoConversion.class.getCanonicalName() + + } + public String getParameterName() { return parameterName; } + String addConverterIfNeeded(String parameterName) { + return !hasConverter() ? parameterName : "new " + getFluentApiBackingBeanMapping().converterAsTypeMirrorWrapper().getQualifiedName() + "().convert(" + parameterName +")"; + } + + public String getAssignmentString() { Optional backBeanField = getBackingBeanField(); @@ -89,9 +103,13 @@ public String getAssignmentString() { if (typeMirrorWrapper.isCollection() || typeMirrorWrapper.isArray()) { typeMirrorWrapper = typeMirrorWrapper.getWrappedComponentType(); } - if (!typeMirrorWrapper.erasure().isAssignableTo(backBeanField.get().getConcreteType().erasure())) { - // must throw validation error - throw new IncompatibleParameterTypeException(type.getSimpleName(),backBeanField.get().getFieldName(),backBeanField.get().getFieldType().getTypeDeclaration(),FluentApiBackingBeanMappingWrapper.wrap(parameterElement.unwrap())); + if (!hasConverter()) { + if (!typeMirrorWrapper.erasure().isAssignableTo(backBeanField.get().getConcreteType().erasure())) { + // must throw validation error + throw new IncompatibleParameterTypeException(type.getSimpleName(), backBeanField.get().getFieldName(), backBeanField.get().getFieldType().getTypeDeclaration(), FluentApiBackingBeanMappingWrapper.wrap(parameterElement.unwrap())); + } + } else { + validateConverter(backBeanField.get()); } // must handle 3 scenarios depending on parameter type: @@ -101,11 +119,11 @@ public String getAssignmentString() { // 3. single value if (type.isArray()) { - return " = new " + backBeanField.get().getCollectionImplType() + "(Arrays.asList(" + getParameterName() + "));"; + return " = new " + backBeanField.get().getCollectionImplType() + "(Arrays.asList(" + addConverterIfNeeded(getParameterName()) + "));"; } else if (type.isCollection()) { - return " = new " + backBeanField.get().getCollectionImplType() + "(" + getParameterName() + ");"; + return " = new " + backBeanField.get().getCollectionImplType() + "(" + addConverterIfNeeded(getParameterName()) + ");"; } else { - return " = new " + backBeanField.get().getCollectionImplType() + "(Collections.singletonList( " + getParameterName() + " ));"; + return " = new " + backBeanField.get().getCollectionImplType() + "(Collections.singletonList( " + addConverterIfNeeded(getParameterName()) + " ));"; } } @@ -117,17 +135,18 @@ public String getAssignmentString() { // 3. single value if (type.isArray()) { - return ".addAll(Arrays.asList(" + getParameterName() + "));"; + return ".addAll(Arrays.asList(" + addConverterIfNeeded(getParameterName()) + "));"; } else if (type.isCollection()) { - return ".addAll(" + getParameterName() + ");"; + return ".addAll(" + addConverterIfNeeded(getParameterName()) + ");"; } else { - return ".add(" + getParameterName() + ");"; + return ".add(" + addConverterIfNeeded(getParameterName()) + ");"; } } } } /*- + else if (backBeanField.get().isArray()) { switch (getFluentApiBackingBeanMapping().action()) { case SET: { @@ -141,8 +160,17 @@ else if (backBeanField.get().isArray()) { else { + if (hasConverter()) { + validateConverter(backBeanField.get()); + } else { + if (!type.erasure().isAssignableTo(backBeanField.get().getFieldType().erasure())) { + // must throw validation error + throw new IncompatibleParameterTypeException(type.getSimpleName(), backBeanField.get().getFieldName(), backBeanField.get().getFieldType().getTypeDeclaration(), FluentApiBackingBeanMappingWrapper.wrap(parameterElement.unwrap())); + } + } + // just parameter assignment - return " = " + getParameterName() +";"; + return " = " + addConverterIfNeeded(getParameterName()) +";"; } } @@ -150,6 +178,19 @@ else if (backBeanField.get().isArray()) { return ""; } + private void validateConverter(ModelBackingBeanField backBeanField) { + TypeMirrorWrapper converter = fluentApiBackingBeanMapping.converterAsTypeMirrorWrapper(); + + TypeMirrorWrapper sourceType = this.parameterElement.asType(); + TypeMirrorWrapper targetType = backBeanField.getFieldType(); + + List converterTypeArguments = InterfaceUtils.getResolvedTypeArgumentOfSuperTypeOrInterface(converter.getTypeElement().get(), TypeMirrorWrapper.wrap(FluentApiConverter.class)); + + if (!sourceType.isAssignableTo(converterTypeArguments.get(0)) + || !converterTypeArguments.get(1).isAssignableTo(targetType)) { + throw new IncompatibleConverterException(fluentApiBackingBeanMapping,sourceType,targetType,converter,converterTypeArguments); + } + } @DeclareCompilerMessage(code = "001", enumValueName = "BB_MAPPING_ANNOTATION_MUST_BE_PRESENT", message = "${0} annotation must be present on parameter", processorClass = FluentApiProcessor.class) @@ -183,7 +224,7 @@ public boolean validate() { try { getAssignmentString(); - } catch (IncompatibleParameterTypeException e) { + } catch (CompilerErrorException e) { e.writeErrorCompilerMessage(); return false; } diff --git a/fluapigen-processor/src/test/java/io/toolisticon/fluapigen/processor/CustomFluentApiBackingBeanWrapperCodeTest.java b/fluapigen-processor/src/test/java/io/toolisticon/fluapigen/processor/CustomFluentApiBackingBeanWrapperCodeTest.java index 2f59ccf..036bc7d 100644 --- a/fluapigen-processor/src/test/java/io/toolisticon/fluapigen/processor/CustomFluentApiBackingBeanWrapperCodeTest.java +++ b/fluapigen-processor/src/test/java/io/toolisticon/fluapigen/processor/CustomFluentApiBackingBeanWrapperCodeTest.java @@ -7,7 +7,6 @@ import io.toolisticon.cute.PassIn; import io.toolisticon.fluapigen.api.FluentApi; import io.toolisticon.fluapigen.api.FluentApiBackingBean; -import io.toolisticon.fluapigen.api.FluentApiInterface; import org.hamcrest.MatcherAssert; import org.junit.Before; import org.junit.Test; diff --git a/fluapigen-processor/src/test/java/io/toolisticon/fluapigen/processor/FluentApiProcessorTest.java b/fluapigen-processor/src/test/java/io/toolisticon/fluapigen/processor/FluentApiProcessorTest.java index 186f897..4ea98c9 100644 --- a/fluapigen-processor/src/test/java/io/toolisticon/fluapigen/processor/FluentApiProcessorTest.java +++ b/fluapigen-processor/src/test/java/io/toolisticon/fluapigen/processor/FluentApiProcessorTest.java @@ -172,7 +172,7 @@ public void test_invalid_MultipleRootInterfaces() { } @Test - public void test_invalid_ImpllicitValue_Int() { + public void test_invalid_ImplicitValue_Int() { compileTestBuilder .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_InvalidImplicitValue_Int.java")) @@ -271,4 +271,128 @@ public void test_invalid_InvalidNumberOfParentMappingsAtCommand() { } + @Test + public void test_valid_ImplicitValueConverter() { + + compileTestBuilder + .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_ImplicitValueConverterTest.java")) + .compilationShouldSucceed() + .executeTest(); + + + } + + @Test + public void test_invalid_ImplicitValueConverter_invalidTargetType() { + + compileTestBuilder + .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidTargetType.java")) + .expectErrorMessage().atSource("/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidTargetType.java").atLineNumber(55L).thatContains(FluentApiProcessorCompilerMessages.ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_TO_TARGET_ATTRIBUTE_TYPE.getCode()) + .expectErrorMessage().atSource("/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidTargetType.java").atLineNumber(58L).thatContains(FluentApiProcessorCompilerMessages.ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_TO_TARGET_ATTRIBUTE_TYPE.getCode()) + .expectErrorMessage().atSource("/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidTargetType.java").atLineNumber(61L).thatContains(FluentApiProcessorCompilerMessages.ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_TO_TARGET_ATTRIBUTE_TYPE.getCode()) + .expectErrorMessage().atSource("/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidTargetType.java").atLineNumber(64L).thatContains(FluentApiProcessorCompilerMessages.ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_TO_TARGET_ATTRIBUTE_TYPE.getCode()) + .compilationShouldFail() + .executeTest(); + + + } + + @Test + public void test_invalid_ImplicitValueConverter_invalidSourceType() { + + compileTestBuilder + .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidSourceType.java")) + .expectErrorMessage().atSource("/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidSourceType.java").atLineNumber(55L).thatContains(FluentApiProcessorCompilerMessages.ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_SOURCE_TYPE_STRING.getCode()) + .expectErrorMessage().atSource("/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidSourceType.java").atLineNumber(58L).thatContains(FluentApiProcessorCompilerMessages.ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_SOURCE_TYPE_STRING.getCode()) + .expectErrorMessage().atSource("/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidSourceType.java").atLineNumber(61L).thatContains(FluentApiProcessorCompilerMessages.ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_SOURCE_TYPE_STRING.getCode()) + .expectErrorMessage().atSource("/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidSourceType.java").atLineNumber(64L).thatContains(FluentApiProcessorCompilerMessages.ERROR_IMPLICIT_VALUE_CONVERTER_MUST_CONVERT_SOURCE_TYPE_STRING.getCode()) + .compilationShouldFail() + .executeTest(); + + + } + + @Test + public void test_valid_BackingBeanMappingConverter() { + + compileTestBuilder + .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_BackingBeanMapping_Converter.java")) + .compilationShouldSucceed() + .executeTest(); + + + } + + @Test + public void test_invalid_BackingBeanMappingConverter_wrongSingleValueSource() { + + compileTestBuilder + .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceSingleValue.java")) + .expectErrorMessage().atLineNumber(62L).thatContains(FluentApiProcessorCompilerMessages.BB_MAPPING_INVALID_CONVERTER.getCode()) + .compilationShouldFail() + .executeTest(); + + + } + + @Test + public void test_invalid_BackingBeanMappingConverter_wrongArrayValueSource() { + + compileTestBuilder + .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceArrayValue.java")) + .expectErrorMessage().atLineNumber(64L).thatContains(FluentApiProcessorCompilerMessages.BB_MAPPING_INVALID_CONVERTER.getCode()) + .compilationShouldFail() + .executeTest(); + + + } + + @Test + public void test_invalid_BackingBeanMappingConverter_wrongCollectionValueSource() { + + compileTestBuilder + .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceCollectionValue.java")) + .expectErrorMessage().atLineNumber(66L).thatContains(FluentApiProcessorCompilerMessages.BB_MAPPING_INVALID_CONVERTER.getCode()) + .compilationShouldFail() + .executeTest(); + + + } + + @Test + public void test_invalid_BackingBeanMappingConverter_wrongSingleValueTarget() { + + compileTestBuilder + .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetSingleValue.java")) + .expectErrorMessage().atLineNumber(62L).thatContains(FluentApiProcessorCompilerMessages.BB_MAPPING_INVALID_CONVERTER.getCode()) + .compilationShouldFail() + .executeTest(); + + + } + + @Test + public void test_invalid_BackingBeanMappingConverter_wrongArrayValueTarget() { + + compileTestBuilder + .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetArrayValue.java")) + .expectErrorMessage().atLineNumber(64L).thatContains(FluentApiProcessorCompilerMessages.BB_MAPPING_INVALID_CONVERTER.getCode()) + .compilationShouldFail() + .executeTest(); + + + } + + @Test + public void test_invalid_BackingBeanMappingConverter_wrongCollectionValueTarget() { + + compileTestBuilder + .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetCollectionValue.java")) + .expectErrorMessage().atLineNumber(66L).thatContains(FluentApiProcessorCompilerMessages.BB_MAPPING_INVALID_CONVERTER.getCode()) + .compilationShouldFail() + .executeTest(); + + + } + } \ No newline at end of file diff --git a/fluapigen-processor/src/test/java/io/toolisticon/fluapigen/processor/ImplicitValueConverterTest.java b/fluapigen-processor/src/test/java/io/toolisticon/fluapigen/processor/ImplicitValueConverterTest.java new file mode 100644 index 0000000..9991a55 --- /dev/null +++ b/fluapigen-processor/src/test/java/io/toolisticon/fluapigen/processor/ImplicitValueConverterTest.java @@ -0,0 +1,76 @@ +package io.toolisticon.fluapigen.processor; + +import io.toolisticon.aptk.common.ToolingProvider; +import io.toolisticon.aptk.tools.InterfaceUtils; +import io.toolisticon.aptk.tools.MessagerUtils; +import io.toolisticon.aptk.tools.TypeMirrorWrapper; +import io.toolisticon.aptk.tools.wrapper.TypeElementWrapper; +import io.toolisticon.cute.CompileTestBuilder; +import io.toolisticon.cute.UnitTest; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import org.junit.Before; +import org.junit.Test; + +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import java.util.List; + +public class ImplicitValueConverterTest { + + CompileTestBuilder.UnitTestBuilder unitTestBuilder; + + + public static class TargetType { + + private final String value; + + public TargetType (String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + } + + public static class MyConverter implements FluentApiConverter { + + @Override + public TargetType convert(String o) { + return new TargetType(o); + } + + } + + @Before + public void init() { + MessagerUtils.setPrintMessageCodes(true); + + unitTestBuilder = CompileTestBuilder + .unitTest(); + } + + @Test + public void test() { + unitTestBuilder.defineTest(new UnitTest() { + @Override + public void unitTest(ProcessingEnvironment processingEnvironment, Element element) { + try { + ToolingProvider.setTooling(processingEnvironment); + + List typeParameters = InterfaceUtils.getResolvedTypeArgumentOfSuperTypeOrInterface(TypeElementWrapper.getByClass(MyConverter.class).get(), TypeMirrorWrapper.wrap(FluentApiConverter.class)); + + System.out.println("XX"); + + } finally { + ToolingProvider.clearTooling(); + } + + + } + }).executeTest(); + } + + +} diff --git a/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter.java b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter.java new file mode 100644 index 0000000..8e2806d --- /dev/null +++ b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter.java @@ -0,0 +1,87 @@ +package io.toolisticon.fluapigen.testcases; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanField; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import io.toolisticon.fluapigen.api.FluentApiParentBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiImplicitValue; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; +import io.toolisticon.fluapigen.api.TargetBackingBean; + +import java.util.List; + +@FluentApi("IntegrationTestStarter") +public class IntegrationTest_BackingBeanMapping_Converter { + + // Backing Bean Interface + @FluentApiBackingBean + interface MyRootLevelBackingBean { + + @FluentApiBackingBeanField("singleValue") + String getSingleValue(); + + @FluentApiBackingBeanField("arrayValue") + String[] getArrayValue(); + + @FluentApiBackingBeanField("collectionValue") + List getCollectionValue(); + + + } + + public static class MySingleValueConverter implements FluentApiConverter { + @Override + public String convert(Long aLong) { + // ignore null safety.. + return aLong.toString(); + } + } + + public static class MyArrayValueConverter implements FluentApiConverter { + @Override + public String[] convert(Long[] aLong) { + // ignore null safety.. + return null; + } + } + + public static class MyCollectionValueConverter implements FluentApiConverter, List> { + @Override + public List convert(List aLong) { + // ignore null safety.. + return null; + } + } + + // Fluent Api interfaces + @FluentApiInterface(MyRootLevelBackingBean.class) + @FluentApiRoot + public interface MyRootInterface { + + MyRootInterface setSingleValue(@FluentApiBackingBeanMapping(value = "singleValue", converter = MySingleValueConverter.class) Long name); + + MyRootInterface setArrayValue(@FluentApiBackingBeanMapping(value = "arrayValue", converter = MyArrayValueConverter.class) Long[] name); + + MyRootInterface setCollectionValue(@FluentApiBackingBeanMapping(value = "collectionValue", converter = MyCollectionValueConverter.class) List name); + + + @FluentApiCommand(MyCommand.class) + void myCommand(); + + + } + + // Commands + @FluentApiCommand + static class MyCommand { + static void myCommand(MyRootLevelBackingBean backingBean) { + System.out.println(backingBean.getSingleValue()); + } + } + + +} \ No newline at end of file diff --git a/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceArrayValue.java b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceArrayValue.java new file mode 100644 index 0000000..da47c5c --- /dev/null +++ b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceArrayValue.java @@ -0,0 +1,84 @@ +package io.toolisticon.fluapigen.testcases; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanField; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; + +import java.util.List; + +@FluentApi("IntegrationTestStarter") +public class IntegrationTest_BackingBeanMapping_Converter_WrongSourceArrayValue { + + // Backing Bean Interface + @FluentApiBackingBean + interface MyRootLevelBackingBean { + + @FluentApiBackingBeanField("singleValue") + String getSingleValue(); + + @FluentApiBackingBeanField("arrayValue") + String[] getArrayValue(); + + @FluentApiBackingBeanField("collectionValue") + List getCollectionValue(); + + + } + + public static class MySingleValueConverter implements FluentApiConverter { + @Override + public String convert(String aLong) { + // ignore null safety.. + return aLong.toString(); + } + } + + public static class MyArrayValueConverter implements FluentApiConverter { + @Override + public String[] convert(Long[] aLong) { + // ignore null safety.. + return null; + } + } + + public static class MyCollectionValueConverter implements FluentApiConverter, List> { + @Override + public List convert(List aLong) { + // ignore null safety.. + return null; + } + } + + // Fluent Api interfaces + @FluentApiInterface(MyRootLevelBackingBean.class) + @FluentApiRoot + public interface MyRootInterface { + + MyRootInterface setSingleValue(@FluentApiBackingBeanMapping(value = "singleValue", converter = MySingleValueConverter.class) Long name); + + MyRootInterface setArrayValue(@FluentApiBackingBeanMapping(value = "arrayValue", converter = MyArrayValueConverter.class) Long[] name); + + MyRootInterface setCollectionValue(@FluentApiBackingBeanMapping(value = "collectionValue", converter = MyCollectionValueConverter.class) List name); + + + @FluentApiCommand(MyCommand.class) + void myCommand(); + + + } + + // Commands + @FluentApiCommand + static class MyCommand { + static void myCommand(MyRootLevelBackingBean backingBean) { + System.out.println(backingBean.getSingleValue()); + } + } + + +} \ No newline at end of file diff --git a/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceCollectionValue.java b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceCollectionValue.java new file mode 100644 index 0000000..94f188b --- /dev/null +++ b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceCollectionValue.java @@ -0,0 +1,84 @@ +package io.toolisticon.fluapigen.testcases; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanField; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; + +import java.util.List; + +@FluentApi("IntegrationTestStarter") +public class IntegrationTest_BackingBeanMapping_Converter_WrongSourceCollectionValue { + + // Backing Bean Interface + @FluentApiBackingBean + interface MyRootLevelBackingBean { + + @FluentApiBackingBeanField("singleValue") + String getSingleValue(); + + @FluentApiBackingBeanField("arrayValue") + String[] getArrayValue(); + + @FluentApiBackingBeanField("collectionValue") + List getCollectionValue(); + + + } + + public static class MySingleValueConverter implements FluentApiConverter { + @Override + public String convert(String aLong) { + // ignore null safety.. + return aLong.toString(); + } + } + + public static class MyArrayValueConverter implements FluentApiConverter { + @Override + public String[] convert(Long[] aLong) { + // ignore null safety.. + return null; + } + } + + public static class MyCollectionValueConverter implements FluentApiConverter, List> { + @Override + public List convert(List aLong) { + // ignore null safety.. + return null; + } + } + + // Fluent Api interfaces + @FluentApiInterface(MyRootLevelBackingBean.class) + @FluentApiRoot + public interface MyRootInterface { + + MyRootInterface setSingleValue(@FluentApiBackingBeanMapping(value = "singleValue", converter = MySingleValueConverter.class) Long name); + + MyRootInterface setArrayValue(@FluentApiBackingBeanMapping(value = "arrayValue", converter = MyArrayValueConverter.class) Long[] name); + + MyRootInterface setCollectionValue(@FluentApiBackingBeanMapping(value = "collectionValue", converter = MyCollectionValueConverter.class) List name); + + + @FluentApiCommand(MyCommand.class) + void myCommand(); + + + } + + // Commands + @FluentApiCommand + static class MyCommand { + static void myCommand(MyRootLevelBackingBean backingBean) { + System.out.println(backingBean.getSingleValue()); + } + } + + +} \ No newline at end of file diff --git a/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceSingleValue.java b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceSingleValue.java new file mode 100644 index 0000000..2485457 --- /dev/null +++ b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongSourceSingleValue.java @@ -0,0 +1,84 @@ +package io.toolisticon.fluapigen.testcases; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanField; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; + +import java.util.List; + +@FluentApi("IntegrationTestStarter") +public class IntegrationTest_BackingBeanMapping_Converter_WrongSourceSingleValue { + + // Backing Bean Interface + @FluentApiBackingBean + interface MyRootLevelBackingBean { + + @FluentApiBackingBeanField("singleValue") + String getSingleValue(); + + @FluentApiBackingBeanField("arrayValue") + String[] getArrayValue(); + + @FluentApiBackingBeanField("collectionValue") + List getCollectionValue(); + + + } + + public static class MySingleValueConverter implements FluentApiConverter { + @Override + public String convert(String aLong) { + // ignore null safety.. + return aLong.toString(); + } + } + + public static class MyArrayValueConverter implements FluentApiConverter { + @Override + public String[] convert(Long[] aLong) { + // ignore null safety.. + return null; + } + } + + public static class MyCollectionValueConverter implements FluentApiConverter, List> { + @Override + public List convert(List aLong) { + // ignore null safety.. + return null; + } + } + + // Fluent Api interfaces + @FluentApiInterface(MyRootLevelBackingBean.class) + @FluentApiRoot + public interface MyRootInterface { + + MyRootInterface setSingleValue(@FluentApiBackingBeanMapping(value = "singleValue", converter = MySingleValueConverter.class) Long name); + + MyRootInterface setArrayValue(@FluentApiBackingBeanMapping(value = "arrayValue", converter = MyArrayValueConverter.class) Long[] name); + + MyRootInterface setCollectionValue(@FluentApiBackingBeanMapping(value = "collectionValue", converter = MyCollectionValueConverter.class) List name); + + + @FluentApiCommand(MyCommand.class) + void myCommand(); + + + } + + // Commands + @FluentApiCommand + static class MyCommand { + static void myCommand(MyRootLevelBackingBean backingBean) { + System.out.println(backingBean.getSingleValue()); + } + } + + +} \ No newline at end of file diff --git a/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetArrayValue.java b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetArrayValue.java new file mode 100644 index 0000000..36f336d --- /dev/null +++ b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetArrayValue.java @@ -0,0 +1,84 @@ +package io.toolisticon.fluapigen.testcases; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanField; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; + +import java.util.List; + +@FluentApi("IntegrationTestStarter") +public class IntegrationTest_BackingBeanMapping_Converter_WrongTargetArrayValue { + + // Backing Bean Interface + @FluentApiBackingBean + interface MyRootLevelBackingBean { + + @FluentApiBackingBeanField("singleValue") + String getSingleValue(); + + @FluentApiBackingBeanField("arrayValue") + String[] getArrayValue(); + + @FluentApiBackingBeanField("collectionValue") + List getCollectionValue(); + + + } + + public static class MySingleValueConverter implements FluentApiConverter { + @Override + public String convert(Long aLong) { + // ignore null safety.. + return aLong.toString(); + } + } + + public static class MyArrayValueConverter implements FluentApiConverter { + @Override + public Long[] convert(Long[] aLong) { + // ignore null safety.. + return null; + } + } + + public static class MyCollectionValueConverter implements FluentApiConverter, List> { + @Override + public List convert(List aLong) { + // ignore null safety.. + return null; + } + } + + // Fluent Api interfaces + @FluentApiInterface(MyRootLevelBackingBean.class) + @FluentApiRoot + public interface MyRootInterface { + + MyRootInterface setSingleValue(@FluentApiBackingBeanMapping(value = "singleValue", converter = MySingleValueConverter.class) Long name); + + MyRootInterface setArrayValue(@FluentApiBackingBeanMapping(value = "arrayValue", converter = MyArrayValueConverter.class) Long[] name); + + MyRootInterface setCollectionValue(@FluentApiBackingBeanMapping(value = "collectionValue", converter = MyCollectionValueConverter.class) List name); + + + @FluentApiCommand(MyCommand.class) + void myCommand(); + + + } + + // Commands + @FluentApiCommand + static class MyCommand { + static void myCommand(MyRootLevelBackingBean backingBean) { + System.out.println(backingBean.getSingleValue()); + } + } + + +} \ No newline at end of file diff --git a/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetCollectionValue.java b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetCollectionValue.java new file mode 100644 index 0000000..1fee3ca --- /dev/null +++ b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetCollectionValue.java @@ -0,0 +1,84 @@ +package io.toolisticon.fluapigen.testcases; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanField; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; + +import java.util.List; + +@FluentApi("IntegrationTestStarter") +public class IntegrationTest_BackingBeanMapping_Converter_WrongTargetCollectionValue { + + // Backing Bean Interface + @FluentApiBackingBean + interface MyRootLevelBackingBean { + + @FluentApiBackingBeanField("singleValue") + String getSingleValue(); + + @FluentApiBackingBeanField("arrayValue") + String[] getArrayValue(); + + @FluentApiBackingBeanField("collectionValue") + List getCollectionValue(); + + + } + + public static class MySingleValueConverter implements FluentApiConverter { + @Override + public String convert(String aLong) { + // ignore null safety.. + return aLong.toString(); + } + } + + public static class MyArrayValueConverter implements FluentApiConverter { + @Override + public String[] convert(Long[] aLong) { + // ignore null safety.. + return null; + } + } + + public static class MyCollectionValueConverter implements FluentApiConverter, List> { + @Override + public List convert(List aLong) { + // ignore null safety.. + return null; + } + } + + // Fluent Api interfaces + @FluentApiInterface(MyRootLevelBackingBean.class) + @FluentApiRoot + public interface MyRootInterface { + + MyRootInterface setSingleValue(@FluentApiBackingBeanMapping(value = "singleValue", converter = MySingleValueConverter.class) Long name); + + MyRootInterface setArrayValue(@FluentApiBackingBeanMapping(value = "arrayValue", converter = MyArrayValueConverter.class) Long[] name); + + MyRootInterface setCollectionValue(@FluentApiBackingBeanMapping(value = "collectionValue", converter = MyCollectionValueConverter.class) List name); + + + @FluentApiCommand(MyCommand.class) + void myCommand(); + + + } + + // Commands + @FluentApiCommand + static class MyCommand { + static void myCommand(MyRootLevelBackingBean backingBean) { + System.out.println(backingBean.getSingleValue()); + } + } + + +} \ No newline at end of file diff --git a/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetSingleValue.java b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetSingleValue.java new file mode 100644 index 0000000..d6c5f3a --- /dev/null +++ b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_BackingBeanMapping_Converter_WrongTargetSingleValue.java @@ -0,0 +1,84 @@ +package io.toolisticon.fluapigen.testcases; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanField; +import io.toolisticon.fluapigen.api.FluentApiBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; + +import java.util.List; + +@FluentApi("IntegrationTestStarter") +public class IntegrationTest_BackingBeanMapping_Converter_WrongTargetSingleValue { + + // Backing Bean Interface + @FluentApiBackingBean + interface MyRootLevelBackingBean { + + @FluentApiBackingBeanField("singleValue") + String getSingleValue(); + + @FluentApiBackingBeanField("arrayValue") + String[] getArrayValue(); + + @FluentApiBackingBeanField("collectionValue") + List getCollectionValue(); + + + } + + public static class MySingleValueConverter implements FluentApiConverter { + @Override + public String convert(Long aLong) { + // ignore null safety.. + return aLong; + } + } + + public static class MyArrayValueConverter implements FluentApiConverter { + @Override + public String[] convert(Long[] aLong) { + // ignore null safety.. + return null; + } + } + + public static class MyCollectionValueConverter implements FluentApiConverter, List> { + @Override + public List convert(List aLong) { + // ignore null safety.. + return null; + } + } + + // Fluent Api interfaces + @FluentApiInterface(MyRootLevelBackingBean.class) + @FluentApiRoot + public interface MyRootInterface { + + MyRootInterface setSingleValue(@FluentApiBackingBeanMapping(value = "singleValue", converter = MySingleValueConverter.class) Long name); + + MyRootInterface setArrayValue(@FluentApiBackingBeanMapping(value = "arrayValue", converter = MyArrayValueConverter.class) Long[] name); + + MyRootInterface setCollectionValue(@FluentApiBackingBeanMapping(value = "collectionValue", converter = MyCollectionValueConverter.class) List name); + + + @FluentApiCommand(MyCommand.class) + void myCommand(); + + + } + + // Commands + @FluentApiCommand + static class MyCommand { + static void myCommand(MyRootLevelBackingBean backingBean) { + System.out.println(backingBean.getSingleValue()); + } + } + + +} \ No newline at end of file diff --git a/fluapigen-processor/src/test/resources/testcases/IntegrationTest_ImplicitValueConverterTest.java b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_ImplicitValueConverterTest.java new file mode 100644 index 0000000..3f21bf2 --- /dev/null +++ b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_ImplicitValueConverterTest.java @@ -0,0 +1,79 @@ +package io.toolisticon.cute; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import io.toolisticon.fluapigen.api.FluentApiImplicitValue; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; +import io.toolisticon.fluapigen.api.MappingAction; + +import java.util.List; + +@FluentApi("ImplicitValueConverterTestBuilder") +public class IntegrationTest_ImplicitValueConverterTest { + + public static class TargetType { + + private final String value; + + public TargetType (String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + } + + public static class MyConverter implements FluentApiConverter { + + @Override + public TargetType convert(String o) { + return new TargetType(o); + } + + } + + @FluentApiBackingBean + public interface TestBackingBean { + + TargetType singleValue(); + + List collectionValue(); + + TargetType[] arrayValue(); + + } + + @FluentApiRoot + @FluentApiInterface(value = TestBackingBean.class) + public interface MyFluentInterface{ + + @FluentApiImplicitValue(id="singleValue", value = "SINGLE", converter = MyConverter.class) + MyFluentInterface setSingleValue(); + + @FluentApiImplicitValue(id = "collectionValue", value={"ONE", "TWO", "THREE"}, action = MappingAction.SET, converter = MyConverter.class) + MyFluentInterface setCollectionValue(); + + @FluentApiImplicitValue(id = "collectionValue", value={"A", "B", "C"}, action = MappingAction.ADD, converter = MyConverter.class) + MyFluentInterface addCollectionValue(); + + @FluentApiImplicitValue(id="arrayValue", value = {"A", "B", "C"},converter = MyConverter.class) + MyFluentInterface setArrayValue(); + + @FluentApiCommand(MyCommand.class) + TestBackingBean myCommand(); + + } + + @FluentApiCommand() + public static class MyCommand { + public static TestBackingBean myCommand(TestBackingBean testBackingBean) { + return testBackingBean; + } + } + +} diff --git a/fluapigen-processor/src/test/resources/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidSourceType.java b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidSourceType.java new file mode 100644 index 0000000..0a88ee7 --- /dev/null +++ b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidSourceType.java @@ -0,0 +1,79 @@ +package io.toolisticon.cute; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import io.toolisticon.fluapigen.api.FluentApiImplicitValue; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; +import io.toolisticon.fluapigen.api.MappingAction; + +import java.util.List; + +@FluentApi("ImplicitValueConverterTestBuilder") +public class IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidSourceType { + + public static class TargetType { + + private final String value; + + public TargetType (String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + } + + public static class MyConverter implements FluentApiConverter { + + @Override + public TargetType convert(Integer o) { + return new TargetType(o.toString()); + } + + } + + @FluentApiBackingBean + public interface TestBackingBean { + + TargetType singleValue(); + + List collectionValue(); + + TargetType[] arrayValue(); + + } + + @FluentApiRoot + @FluentApiInterface(value = TestBackingBean.class) + public interface MyFluentInterface{ + + @FluentApiImplicitValue(id="singleValue", value = "SINGLE", converter = MyConverter.class) + MyFluentInterface setSingleValue(); + + @FluentApiImplicitValue(id = "collectionValue", value={"ONE", "TWO", "THREE"}, action = MappingAction.SET, converter = MyConverter.class) + MyFluentInterface setCollectionValue(); + + @FluentApiImplicitValue(id = "collectionValue", value={"A", "B", "C"}, action = MappingAction.ADD, converter = MyConverter.class) + MyFluentInterface addCollectionValue(); + + @FluentApiImplicitValue(id="arrayValue", value = {"A", "B", "C"},converter = MyConverter.class) + MyFluentInterface setArrayValue(); + + @FluentApiCommand(MyCommand.class) + TestBackingBean myCommand(); + + } + + @FluentApiCommand() + public static class MyCommand { + public static TestBackingBean myCommand(TestBackingBean testBackingBean) { + return testBackingBean; + } + } + +} diff --git a/fluapigen-processor/src/test/resources/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidTargetType.java b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidTargetType.java new file mode 100644 index 0000000..8184352 --- /dev/null +++ b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidTargetType.java @@ -0,0 +1,79 @@ +package io.toolisticon.cute; + +import io.toolisticon.fluapigen.api.FluentApi; +import io.toolisticon.fluapigen.api.FluentApiBackingBean; +import io.toolisticon.fluapigen.api.FluentApiCommand; +import io.toolisticon.fluapigen.api.FluentApiConverter; +import io.toolisticon.fluapigen.api.FluentApiImplicitValue; +import io.toolisticon.fluapigen.api.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiRoot; +import io.toolisticon.fluapigen.api.MappingAction; + +import java.util.List; + +@FluentApi("ImplicitValueConverterTestBuilder") +public class IntegrationTest_ImplicitValueConverterTest_withInvalidConverter_invalidTargetType { + + public static class TargetType { + + private final String value; + + public TargetType (String value) { + this.value = value; + } + + @Override + public String toString() { + return this.value; + } + } + + public static class MyConverter implements FluentApiConverter { + + @Override + public String convert(String o) { + return o; + } + + } + + @FluentApiBackingBean + public interface TestBackingBean { + + TargetType singleValue(); + + List collectionValue(); + + TargetType[] arrayValue(); + + } + + @FluentApiRoot + @FluentApiInterface(value = TestBackingBean.class) + public interface MyFluentInterface{ + + @FluentApiImplicitValue(id="singleValue", value = "SINGLE", converter = MyConverter.class) + MyFluentInterface setSingleValue(); + + @FluentApiImplicitValue(id = "collectionValue", value={"ONE", "TWO", "THREE"}, action = MappingAction.SET, converter = MyConverter.class) + MyFluentInterface setCollectionValue(); + + @FluentApiImplicitValue(id = "collectionValue", value={"A", "B", "C"}, action = MappingAction.ADD, converter = MyConverter.class) + MyFluentInterface addCollectionValue(); + + @FluentApiImplicitValue(id="arrayValue", value = {"A", "B", "C"},converter = MyConverter.class) + MyFluentInterface setArrayValue(); + + @FluentApiCommand(MyCommand.class) + TestBackingBean myCommand(); + + } + + @FluentApiCommand() + public static class MyCommand { + public static TestBackingBean myCommand(TestBackingBean testBackingBean) { + return testBackingBean; + } + } + +} diff --git a/pom.xml b/pom.xml index a752bed..6ab0943 100644 --- a/pom.xml +++ b/pom.xml @@ -73,7 +73,7 @@ 0.12.1 0.11.0 - 0.21.0 + 0.22.3 4.13.2 @@ -81,7 +81,8 @@ 5.2.0 - https://oss.sonatype.org/content/repositories/snapshots/ + https://oss.sonatype.org/content/repositories/snapshots/ +