diff --git a/README.md b/README.md index e34f5a5..d90913e 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,6 @@ All you have to do is to define a bunch of interfaces and to configure its "plum # Restrictions - fluent interfaces must not contain any cycles and must be strongly hierarchically -- fluent interfaces doesn't support parent interfaces at the moment, a solution to support this is currently in work. # How does it work? @@ -367,6 +366,100 @@ Default methods will be ignored during processing of fluent api and backing bean - 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. +### Using parent interfaces to share method declarations and backing bean fields declarations +It's possible to use parent interfaces to share fluent api method declarations in multiple interfaces: + +```java + @FluentApiBackingBean + interface MyRootLevelBackingBean { + + @FluentApiBackingBeanField("1st") + FirstInheritedBackingBean get1st(); + + @FluentApiBackingBeanField("2nd") + SecondInheritedBackingBean get2nd(); + + } + + + // Parent backing bean interface must not be annotated with FluentApiBackingBean annotation + interface MyReusedBackingBeanFields { + + @FluentApiBackingBeanField("name") + String getName(); + + } + + + @FluentApiBackingBean + interface FirstInheritedBackingBean extends MyReusedBackingBeanFields { + + @FluentApiBackingBeanField("1st") + String get1st(); + + } + + @FluentApiBackingBean + interface SecondInheritedBackingBean extends MyReusedBackingBeanFields { + + @FluentApiBackingBeanField("2nd") + String get2nd(); + + } + + + // Fluent Api interfaces + @FluentApiInterface(MyRootLevelBackingBean.class) + @FluentApiRoot + public interface MyRootInterface { + + My1stInterface goto1st(); + + My2ndInterface goto2nd(); + + @FluentApiCommand(MyCommand.class) + void myCommand(); + + + } + + // Parent fluent api interface must not be annotated with FluentApiInterface + // There must be a related backing bean interface for related attributes + // Type Parameters must be used to pass in the followup fluent api interfaces + public interface SharedInterface { + + // Fluebt followup interface must be returned as type variable + FLUENT_INTERFACE setName(@FluentApiBackingBeanMapping(value = "name") String name); + + } + + + @FluentApiInterface(FirstInheritedBackingBean.class) + public interface My1stInterface extends SharedInterface { + + @FluentApiParentBackingBeanMapping("1st") + MyRootInterface set1st(@FluentApiBackingBeanMapping(value = "1st") String first); + + } + + @FluentApiInterface(SecondInheritedBackingBean.class) + public interface My2ndInterface extends SharedInterface { + + @FluentApiParentBackingBeanMapping("2nd") + MyRootInterface set1st(@FluentApiBackingBeanMapping(value = "2nd") String second); + + } + + // Commands + @FluentApiCommand + static class MyCommand { + static void myCommand(MyRootLevelBackingBean backingBean) { + System.out.println("CHECK"); + } + } +``` + + # Contributing We welcome any kind of suggestions and pull requests. diff --git a/fluapigen-api/pom.xml b/fluapigen-api/pom.xml index d7fe673..e0db9e9 100644 --- a/fluapigen-api/pom.xml +++ b/fluapigen-api/pom.xml @@ -9,7 +9,7 @@ io.toolisticon.fluapigen fluapigen - 0.6.0 + 0.7.0 fluapigen-api diff --git a/fluapigen-example/pom.xml b/fluapigen-example/pom.xml index ad93a2d..ac5bba6 100644 --- a/fluapigen-example/pom.xml +++ b/fluapigen-example/pom.xml @@ -9,7 +9,7 @@ io.toolisticon.fluapigen fluapigen - 0.6.0 + 0.7.0 fluapigen-example diff --git a/fluapigen-integrationTest/pom.xml b/fluapigen-integrationTest/pom.xml index 1e09827..f0a37cd 100644 --- a/fluapigen-integrationTest/pom.xml +++ b/fluapigen-integrationTest/pom.xml @@ -9,7 +9,7 @@ io.toolisticon.fluapigen fluapigen - 0.6.0 + 0.7.0 fluapigen-integrationTest diff --git a/fluapigen-integrationTest/src/main/java/io/toolisticon/fluapigen/integrationtest/IntegrationTest_Inheritance_reusingInterfaces.java b/fluapigen-integrationTest/src/main/java/io/toolisticon/fluapigen/integrationtest/IntegrationTest_Inheritance_reusingInterfaces.java new file mode 100644 index 0000000..4e2ec91 --- /dev/null +++ b/fluapigen-integrationTest/src/main/java/io/toolisticon/fluapigen/integrationtest/IntegrationTest_Inheritance_reusingInterfaces.java @@ -0,0 +1,104 @@ +package io.toolisticon.fluapigen.integrationtest; + +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.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiParentBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiRoot; + +import java.io.Serializable; + +@FluentApi("InheritanceIntegrationTestStarter") +public class IntegrationTest_Inheritance_reusingInterfaces { + + // Backing Bean Interface + @FluentApiBackingBean + interface MyRootLevelBackingBean { + + @FluentApiBackingBeanField("1st") + FirstInheritedBackingBean get1st(); + + @FluentApiBackingBeanField("2nd") + SecondInheritedBackingBean get2nd(); + + } + + + interface MyReusedBackingBeanFields { + + @FluentApiBackingBeanField("name") + String getName(); + + } + + + @FluentApiBackingBean + interface FirstInheritedBackingBean extends MyReusedBackingBeanFields { + + @FluentApiBackingBeanField("1st") + String get1st(); + + } + + @FluentApiBackingBean + interface SecondInheritedBackingBean extends MyReusedBackingBeanFields { + + @FluentApiBackingBeanField("2nd") + String get2nd(); + + } + + + // Fluent Api interfaces + @FluentApiInterface(MyRootLevelBackingBean.class) + @FluentApiRoot + public interface MyRootInterface { + + My1stInterface goto1st(); + + My2ndInterface goto2nd(); + + @FluentApiCommand(MyCommand.class) + MyRootLevelBackingBean myCommand(); + + + } + + + public interface SharedInterface { + + FLUENT_INTERFACE setName(@FluentApiBackingBeanMapping(value = "name") String name); + + } + + + @FluentApiInterface(FirstInheritedBackingBean.class) + public interface My1stInterface extends SharedInterface { + + @FluentApiParentBackingBeanMapping("1st") + MyRootInterface set1st(@FluentApiBackingBeanMapping(value = "1st") String first); + + } + + @FluentApiInterface(SecondInheritedBackingBean.class) + public interface My2ndInterface extends SharedInterface { + + @FluentApiParentBackingBeanMapping("2nd") + MyRootInterface set1st(@FluentApiBackingBeanMapping(value = "2nd") String second); + + } + + // Commands + @FluentApiCommand + static class MyCommand { + static MyRootLevelBackingBean myCommand(MyRootLevelBackingBean backingBean) { + System.out.println("CHECK"); + return backingBean; + } + } + + +} \ No newline at end of file diff --git a/fluapigen-integrationTest/src/test/java/io/toolisticon/fluapigen/integrationtest/IntegrationTestTest.java b/fluapigen-integrationTest/src/test/java/io/toolisticon/fluapigen/integrationtest/IntegrationTestTest.java index 96316d3..f935902 100644 --- a/fluapigen-integrationTest/src/test/java/io/toolisticon/fluapigen/integrationtest/IntegrationTestTest.java +++ b/fluapigen-integrationTest/src/test/java/io/toolisticon/fluapigen/integrationtest/IntegrationTestTest.java @@ -353,4 +353,10 @@ public void test_fluentApi_test_toParentTraversal() { } + @Test + public void testInheritance() { + IntegrationTest_Inheritance_reusingInterfaces.MyRootLevelBackingBean bb = InheritanceIntegrationTestStarter.goto1st().setName("1stName").set1st("1").goto2nd().setName("2ndName").set1st("2").myCommand(); + MatcherAssert.assertThat(bb, Matchers.notNullValue()); + } + } diff --git a/fluapigen-processor/pom.xml b/fluapigen-processor/pom.xml index c71ff80..55a651f 100644 --- a/fluapigen-processor/pom.xml +++ b/fluapigen-processor/pom.xml @@ -9,7 +9,7 @@ io.toolisticon.fluapigen fluapigen - 0.6.0 + 0.7.0 fluapigen-processor diff --git a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelBackingBean.java b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelBackingBean.java index 508a12e..41fc936 100644 --- a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelBackingBean.java +++ b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelBackingBean.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.corematcher.AptkCoreMatchers; import io.toolisticon.aptk.tools.wrapper.ElementWrapper; import io.toolisticon.aptk.tools.wrapper.ExecutableElementWrapper; +import io.toolisticon.aptk.tools.wrapper.TypeElementWrapper; import javax.lang.model.element.Modifier; +import javax.lang.model.element.TypeElement; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; @@ -25,6 +28,12 @@ public class ModelBackingBean implements FetchImports, Validatable{ ModelBackingBean(FluentApiBackingBeanWrapper wrapper) { this.wrapper = wrapper; + fields = InterfaceUtils.getMethodsToImplement(TypeElementWrapper.wrap((TypeElement) wrapper._annotatedElement())) + .stream().filter(e -> !e.isDefault()) + .map(ModelBackingBeanField::new) + .collect(Collectors.toList()); + + /*- fields = ElementWrapper.wrap(wrapper._annotatedElement()) .filterEnclosedElements().applyFilter(AptkCoreMatchers.IS_METHOD) .applyFilter(AptkCoreMatchers.BY_MODIFIER).filterByNoneOf(Modifier.DEFAULT).getResult() @@ -33,6 +42,8 @@ public class ModelBackingBean implements FetchImports, Validatable{ .map(ModelBackingBeanField::new) .collect(Collectors.toList()); + */ + // init render state helper RenderStateHelper.addBackingBeanModel(this); diff --git a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterface.java b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterface.java index adad688..cc37a9a 100644 --- a/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterface.java +++ b/fluapigen-processor/src/main/java/io/toolisticon/fluapigen/processor/ModelInterface.java @@ -1,6 +1,7 @@ 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.TypeUtils; import io.toolisticon.aptk.tools.corematcher.AptkCoreMatchers; @@ -35,8 +36,16 @@ public class ModelInterface implements FetchImports, Validatable { this.wrapper = wrapper; this.backingBeanModel = backingBeanModel; + + for (ExecutableElementWrapper executableElement : InterfaceUtils.getMethodsToImplement(TypeElementWrapper.wrap((TypeElement) this.wrapper._annotatedElement())) ){ + + if (executableElement.isDefault()) { + // ignore default methods + continue; + } + //} // get Methods - for (ExecutableElementWrapper executableElement : FluentElementFilter.createFluentElementFilter(this.wrapper._annotatedElement().getEnclosedElements()).applyFilter(AptkCoreMatchers.IS_METHOD).applyFilter(AptkCoreMatchers.BY_MODIFIER).filterByNoneOf(Modifier.DEFAULT).getResult().stream().map(ExecutableElementWrapper::wrap).collect(Collectors.toList())) { + //for (ExecutableElementWrapper executableElement : FluentElementFilter.createFluentElementFilter(this.wrapper._annotatedElement().getEnclosedElements()).applyFilter(AptkCoreMatchers.IS_METHOD).applyFilter(AptkCoreMatchers.BY_MODIFIER).filterByNoneOf(Modifier.DEFAULT).getResult().stream().map(ExecutableElementWrapper::wrap).collect(Collectors.toList())) { methods.add(new ModelInterfaceMethod(executableElement, backingBeanModel)); } 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 4ea98c9..39301d9 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 @@ -395,4 +395,15 @@ public void test_invalid_BackingBeanMappingConverter_wrongCollectionValueTarget( } + @Test + public void test_Inheritance_reusingInterfaces() { + + compileTestBuilder + .addSources(JavaFileObjectUtils.readFromResource("testcases/IntegrationTest_Inheritance_reusingInterfaces.java")) + .compilationShouldSucceed() + .executeTest(); + + + } + } \ No newline at end of file diff --git a/fluapigen-processor/src/test/resources/testcases/IntegrationTest_Inheritance_reusingInterfaces.java b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_Inheritance_reusingInterfaces.java new file mode 100644 index 0000000..d09ae15 --- /dev/null +++ b/fluapigen-processor/src/test/resources/testcases/IntegrationTest_Inheritance_reusingInterfaces.java @@ -0,0 +1,103 @@ +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.FluentApiInterface; +import io.toolisticon.fluapigen.api.FluentApiParentBackingBeanMapping; +import io.toolisticon.fluapigen.api.FluentApiRoot; + +import java.io.Serializable; + +@FluentApi("IntegrationTestStarter") +public class IntegrationTest_Inheritance_reusingInterfaces { + + // Backing Bean Interface + @FluentApiBackingBean + interface MyRootLevelBackingBean { + + @FluentApiBackingBeanField("1st") + FirstInheritedBackingBean get1st(); + + @FluentApiBackingBeanField("2nd") + SecondInheritedBackingBean get2nd(); + + } + + + interface MyReusedBackingBeanFields { + + @FluentApiBackingBeanField("name") + String getName(); + + } + + + @FluentApiBackingBean + interface FirstInheritedBackingBean extends MyReusedBackingBeanFields { + + @FluentApiBackingBeanField("1st") + String get1st(); + + } + + @FluentApiBackingBean + interface SecondInheritedBackingBean extends MyReusedBackingBeanFields { + + @FluentApiBackingBeanField("2nd") + String get2nd(); + + } + + + // Fluent Api interfaces + @FluentApiInterface(MyRootLevelBackingBean.class) + @FluentApiRoot + public interface MyRootInterface { + + My1stInterface goto1st(); + + My2ndInterface goto2nd(); + + @FluentApiCommand(MyCommand.class) + void myCommand(); + + + } + + + public interface SharedInterface { + + FLUENT_INTERFACE setName(@FluentApiBackingBeanMapping(value = "name") String name); + + } + + + @FluentApiInterface(FirstInheritedBackingBean.class) + public interface My1stInterface extends SharedInterface { + + @FluentApiParentBackingBeanMapping("1st") + MyRootInterface set1st(@FluentApiBackingBeanMapping(value = "1st") String first); + + } + + @FluentApiInterface(SecondInheritedBackingBean.class) + public interface My2ndInterface extends SharedInterface { + + @FluentApiParentBackingBeanMapping("2nd") + MyRootInterface set1st(@FluentApiBackingBeanMapping(value = "2nd") String second); + + } + + // Commands + @FluentApiCommand + static class MyCommand { + static void myCommand(MyRootLevelBackingBean backingBean) { + System.out.println("CHECK"); + } + } + + +} \ No newline at end of file diff --git a/pom.xml b/pom.xml index 1ff798e..d1e76a3 100644 --- a/pom.xml +++ b/pom.xml @@ -5,7 +5,7 @@ io.toolisticon.fluapigen fluapigen - 0.6.0 + 0.7.0 pom fluapigen @@ -73,7 +73,7 @@ 0.12.1 0.11.0 - 0.22.3 + 0.22.5 4.13.2