Repository: isis Updated Branches: refs/heads/maint-1.13.2 856d1117f -> fa36da4a4
ISIS-1548: extends @Mixin and @DomainObject to accept (mixin)method() attribute; updates facets; updates algorithm for inferring mixin name/id based on when the name of the method being processed matches this attribute (rather than hard-coded "$$" as previously). Also, supports using "$" (as well as "_") as the separator for MixinType_mixinName (ie for nested static classes). Most of the stuff in ObjectMemberAbstract, plus the three Mixin classes, ObjectActionMixedIn, OneToOneAssociationMixedIn, OneToManyAssociationMixedIn. Project: http://git-wip-us.apache.org/repos/asf/isis/repo Commit: http://git-wip-us.apache.org/repos/asf/isis/commit/147f4c5d Tree: http://git-wip-us.apache.org/repos/asf/isis/tree/147f4c5d Diff: http://git-wip-us.apache.org/repos/asf/isis/diff/147f4c5d Branch: refs/heads/maint-1.13.2 Commit: 147f4c5d4a4eb7541b06a628b7d666bc5169c4f5 Parents: 856d111 Author: Dan Haywood <d...@haywood-associates.co.uk> Authored: Thu Dec 1 10:19:52 2016 +0000 Committer: Dan Haywood <d...@haywood-associates.co.uk> Committed: Thu Dec 1 10:19:52 2016 +0000 ---------------------------------------------------------------------- .../asciidoc/guides/_rgant-DomainObject.adoc | 6 + .../guides/_rgant-DomainObject_mixinMethod.adoc | 40 ++++ .../src/main/asciidoc/guides/_rgant-Mixin.adoc | 44 ++-- .../asciidoc/guides/_rgant-Mixin_method.adoc | 41 ++++ .../guides/_ugbtb_decoupling_mixins.adoc | 231 +++++++++++++------ .../isis/applib/annotation/DomainObject.java | 12 +- .../apache/isis/applib/annotation/Mixin.java | 23 ++ .../facets/object/mixin/MixinFacet.java | 7 +- .../facets/object/mixin/MixinFacetAbstract.java | 8 +- .../MixinFacetForDomainObjectAnnotation.java | 6 +- .../mixin/MixinFacetForMixinAnnotation.java | 6 +- .../specloader/specimpl/MixedInMember.java | 20 +- .../specimpl/ObjectActionMixedIn.java | 4 +- .../specimpl/ObjectMemberAbstract.java | 32 ++- .../specimpl/ObjectSpecificationAbstract.java | 20 +- .../specimpl/OneToManyAssociationMixedIn.java | 4 +- .../specimpl/OneToOneAssociationMixedIn.java | 4 +- .../application/integtests/Smoke_IntegTest.java | 6 +- .../modules/simple/dom/impl/SimpleObject.java | 20 +- .../tests/SimpleObject_IntegTest.java | 4 +- 20 files changed, 367 insertions(+), 171 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/adocs/documentation/src/main/asciidoc/guides/_rgant-DomainObject.adoc ---------------------------------------------------------------------- diff --git a/adocs/documentation/src/main/asciidoc/guides/_rgant-DomainObject.adoc b/adocs/documentation/src/main/asciidoc/guides/_rgant-DomainObject.adoc index 5fa5f91..90f90b2 100644 --- a/adocs/documentation/src/main/asciidoc/guides/_rgant-DomainObject.adoc +++ b/adocs/documentation/src/main/asciidoc/guides/_rgant-DomainObject.adoc @@ -55,6 +55,12 @@ xref:rgsvc.adoc#_rgsvc_spi_AuditerService[`AuditerService`] |whether the object's properties and collections can be edited or not (ie whether the instance should be considered to be immutable) +|xref:rgant.adoc#_rgant-DomainObject_mixinMethod[`mixinMethod()`] +|Method name within the mixin +|(As of `1.13.2-SNAPSHOT`) How to recognize the "reserved" method name, meaning that the mixin's own name will be inferred from the mixin type. +Typical examples are "exec", "execute", "invoke", "apply" and so on. + + |xref:rgant.adoc#_rgant-DomainObject_nature[`nature()`] |`NOT_SPECIFIED`, `JDO_ENTITY`, `EXTERNAL_ENTITY`, `INMEMORY_ENTITY`, `MIXIN`, `VIEW_MODEL` (`NOT_SPECIFIED`) |whether the domain object logically is an entity (part of the domain layer) or is a view model (part of the application layer); or is a mixin. If an entity, indicates how its persistence is managed. http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/adocs/documentation/src/main/asciidoc/guides/_rgant-DomainObject_mixinMethod.adoc ---------------------------------------------------------------------- diff --git a/adocs/documentation/src/main/asciidoc/guides/_rgant-DomainObject_mixinMethod.adoc b/adocs/documentation/src/main/asciidoc/guides/_rgant-DomainObject_mixinMethod.adoc new file mode 100644 index 0000000..cabce49 --- /dev/null +++ b/adocs/documentation/src/main/asciidoc/guides/_rgant-DomainObject_mixinMethod.adoc @@ -0,0 +1,40 @@ +[[_rgant-DomainObject_mixinMethod]] += `mixinMethod()` (`1.13.2-SNAPSHOT`) +:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +:_basedir: ../ +:_imagesdir: images/ + + + +The `mixinMethod()` attribute specifies the name of the method to be treated as a "reserved" method name, meaning that the mixin's name should instead be inferred from the mixin's type. + +For example: + +[source,java] +---- +@DomainObject +public class Customer { + + @DomainObject(nature=Nature.MIXIN, mixinMethod="execute") + public static class _placeOrder { + + Customer customer; + public _placeOrder(Customer customer) { this.customer = customer; } + + public Customer execute(Product p, int quantity) { ... } + public String disableExecute() { ... } + public String validate0Execute() { ... } + } + ... +) +---- + +This allows all mixins to follow a similar convention, with the name of the mixin inferred entirely from its type ("placeOrder"). + +When invoked programmatically, the code reads: + +[source,java] +---- +mixin(Customer._placeOrder.class, someCustomer).execute(someProduct, 3); +---- + http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/adocs/documentation/src/main/asciidoc/guides/_rgant-Mixin.adoc ---------------------------------------------------------------------- diff --git a/adocs/documentation/src/main/asciidoc/guides/_rgant-Mixin.adoc b/adocs/documentation/src/main/asciidoc/guides/_rgant-Mixin.adoc index 427c783..b0937e7 100644 --- a/adocs/documentation/src/main/asciidoc/guides/_rgant-Mixin.adoc +++ b/adocs/documentation/src/main/asciidoc/guides/_rgant-Mixin.adoc @@ -6,35 +6,29 @@ -The `@Mixin` annotation indicates that the class acts as a mixin, contributing behaviour - -actions, (derived) properties and (derived) collections - to another domain object. - -For example: - -[source,java] ----- -@Mixin -public class DocumentHolder_documents { - private final DocumentHolder holder; - public DocumentHolder_documents(DocumentHolder holder) { - this.holder = holder; - } - @Action(semantics=SemanticsOf.SAFE) - @ActionLayout(contributed = Contributed.AS_ASSOCIATION) - @CollectionLayout(render = RenderType.EAGERLY) - public List<Document> documents() { - ... // <1> - } -} ----- -<1> for example, using the (non-ASF) http://github.com/isisaddons/isis-module-poly[Isis addons' poly] module. +The `@Mixin` annotation indicates that the class acts as a mixin, contributing behaviour - actions, (derived) properties and (derived) collections - to another domain object. +Mixins were originally introduced as a means of allowing contributions from one module to the types of another module; in such cases the mixin type is often an interface type (eg `DocumentHolder`) that might be implemented by numerous different concrete types. +However, mixins are also a convenient mechanism for grouping functionality even for a concrete type. -An alternative and equivalent approach is to use the -xref:rgant.adoc#_rgant-DomainObject_nature[`@DomainObject#nature()`] annotation with a nature of `MIXIN`. +For further discussion on using mixins, see xref:ugbtb.adoc#_ugbtb_decoupling_mixins[mixins] in the user guide. +The table below summarizes the annotation's attributes. + +.`@Mixin` attributes +[cols="2,2,4a", options="header"] +|=== -For further discussion on using mixins, see xref:ugbtb.adoc#_ugbtb_decoupling_mixins[mixins] in the user guide. +|xref:rgant.adoc#_rgant-Mixin_method[`method()`] +|Method name within the mixin +|(As of `1.13.2-SNAPSHOT`) How to recognize the "reserved" method name, meaning that the mixin's own name will be inferred from the mixin type. +Typical examples are "exec", "execute", "invoke", "apply" and so on. + +|=== + +An alternative and equivalent approach is to use the +xref:rgant.adoc#_rgant-DomainObject_nature[`@DomainObject#nature()`] annotation with a nature of `MIXIN`. +include::_rgant-Mixin_method.adoc[leveloffset=+1] http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/adocs/documentation/src/main/asciidoc/guides/_rgant-Mixin_method.adoc ---------------------------------------------------------------------- diff --git a/adocs/documentation/src/main/asciidoc/guides/_rgant-Mixin_method.adoc b/adocs/documentation/src/main/asciidoc/guides/_rgant-Mixin_method.adoc new file mode 100644 index 0000000..db8e70b --- /dev/null +++ b/adocs/documentation/src/main/asciidoc/guides/_rgant-Mixin_method.adoc @@ -0,0 +1,41 @@ +[[_rgant-Mixin_method]] += `method()` (`1.13.2-SNAPSHOT`) +:Notice: Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at. http://www.apache.org/licenses/LICENSE-2.0 . Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. +:_basedir: ../ +:_imagesdir: images/ + + + +The `method()` attribute specifies the name of the method to be treated as a "reserved" method name, meaning that the mixin's name should instead be inferred from the mixin's type. + +For example: + +[source,java] +---- +@DomainObject +public class Customer { + + @Mixin(method="execute") + public static class _placeOrder { + + Customer customer; + public _placeOrder(Customer customer) { this.customer = customer; } + + public Customer execute(Product p, int quantity) { ... } + public String disableExecute() { ... } + public String validate0Execute() { ... } + } + ... +) +---- + +This allows all mixins to follow a similar convention, with the name of the mixin inferred entirely from its type ("placeOrder"). + +When invoked programmatically, the code reads: + +[source,java] +---- +mixin(Customer._placeOrder.class, someCustomer).execute(someProduct, 3); +---- + + http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/adocs/documentation/src/main/asciidoc/guides/_ugbtb_decoupling_mixins.adoc ---------------------------------------------------------------------- diff --git a/adocs/documentation/src/main/asciidoc/guides/_ugbtb_decoupling_mixins.adoc b/adocs/documentation/src/main/asciidoc/guides/_ugbtb_decoupling_mixins.adoc index 2013fc9..499733a 100644 --- a/adocs/documentation/src/main/asciidoc/guides/_ugbtb_decoupling_mixins.adoc +++ b/adocs/documentation/src/main/asciidoc/guides/_ugbtb_decoupling_mixins.adoc @@ -5,129 +5,216 @@ :_imagesdir: images/ -A mixin object allows one class to contribute behaviour - actions, (derived) properties and -(derived) collections - to another domain object, either a domain entity or view model. +A mixin object allows one class to contribute behaviour - actions, (derived) properties and (derived) collections - to another domain object, either a domain entity or view model. -Some programming languages use the term "trait" instead of mixin, and some languages (such as AspectJ) define their own -syntax for defining such constructs. In Apache Isis a mixin is very similar to a domain service, however it also -defines a single 1-arg constructor that defines the type of the domain objects that it contributes to. +Some programming languages use the term "trait" instead of mixin, and some languages (such as AspectJ) define their own syntax for defining such constructs. +In Apache Isis a mixin is very similar to a domain service, however it also defines a single 1-arg constructor that defines the type of the domain objects that it contributes to. -Why do this? The main reason is to allow the app to be decoupled, so that it doesn't degrade into the proverbial -link:http://www.laputan.org/mud/mud.html#BigBallOfMud["big ball of mud"]. Mixins (and contributions) allow dependency -to be inverted, so that the dependencies between modules can be kept acyclic and under control. +Why do this? +Two reasons: +* The main reason is to allow the app to be decoupled, so that it doesn't degrade into the proverbial link:http://www.laputan.org/mud/mud.html#BigBallOfMud["big ball of mud"]. +Mixins (and contributions) allow dependency to be inverted, so that the dependencies between modules can be kept acyclic and under control. +* However, there is another reason: mixins are also a convenient mechanism for grouping functionality even for a concrete type, helping to rationalize about the dependency between the data and the behaviour. -== Example +Both use cases are discussed below. -This is probably best explained by way of an example. Suppose we have the `Customer` domain object which implements -a `DocumentHolder` interface: +Syntactically, a mixin is defined using either the xref:rgant.adoc#_rgant_Mixin[`@Mixin`] annotation or using xref:rgant.adoc#_rgant_DomainObject_nature[`@DomainObject#nature()`] attribute (specifying a nature of `Nature.MIXIN`). + + +== Contributed Collection + +The example below shows how to contribute a collection: [source,java] ---- -public class Customer implements DocumentHolder { - ... +@Mixin +public class DocumentHolderDocuments { + + private final DocumentHolder holder; + public DocumentHolderDocuments(DocumentHolder holder) { this.holder = holder; } + + @Action(semantics=SemanticsOf.SAFE) // <1> + @ActionLayout(contributed = Contributed.AS_ASSOCIATION) // <2> + @CollectionLayout(render = RenderType.EAGERLY) + public List<Document> documents() { // <3> + ... + } + public boolean hideDocuments() { ... } // <4> } ---- +<1> required; actions that have side-effects cannot be contributed as collections +<2> required; otherwise the mixin will default to being rendered as an action +<3> must accept no arguments. + The mixin is a collection rather than a property because the return type is a collection, not a scalar. +<4> supporting methods follow the usual naming conventions. + (That said, in the case of collections, because the collection is derived/read-only, the only supporting method that is relevant is `hideXxx()`). + +The above will result in a contributed collection for all types that implement/extend from `DocumentHolder` (so is probably for a mixin across modules). + + +== Contributed Property -We could then imagine a mixin that would contribute behaviour to list, add and remove the ``Document``s for this holder: +Contributed properties are defined similarly, for example: [source,java] ---- -@Mixin // <1> -public class DocumentHolder_documents { +@Mixin +public class DocumentHolderMostRecentDocument { + private final DocumentHolder holder; - public DocumentHolder_documents(DocumentHolder holder) { // <2> - this.holder = holder; - } - @Action(semantics=SemanticsOf.SAFE) - @ActionLayout(contributed = Contributed.AS_ASSOCIATION) - @CollectionLayout(render = RenderType.EAGERLY) - public List<Document> documents() { - ... // <3> - } - @Action(semantics=SemanticsOf.IDEMPOTENT) - public DocumentHolder add(Document document) { - ... // <4> - } - @Action(semantics=SemanticsOf.IDEMPOTENT) - public DocumentHolder remove(Document document) { - ... // <5> + public DocumentHolderDocuments(DocumentHolder holder) { this.holder = holder; } + + @Action(semantics=SemanticsOf.SAFE) // <1> + @ActionLayout(contributed = Contributed.AS_ASSOCIATION) // <2> + public Document> mostRecentDocument() { // <3> + ... } + public boolean hideMostRecentDocument() { ... } // <4> } ---- -<1> alternatively can use `@DomainObject(nature=Nature.MIXIN)` -<2> constructor indicates the type that is contributed to -<3> implementation could, for example, use the (non-ASF) -http://github.com/isisaddons/isis-module-poly[Isis addons' poly] module. -<4> implementation would probably delegate to an injected repository to (ultimately) insert data into some table -<5> implementation would probably delegate to an injected repository to (ultimately) delete data from some table +<1> required; actions that have side-effects cannot be contributed as collections +<2> required; otherwise the mixin will default to being rendered as an action +<3> must accept no arguments. + The mixin is a property rather than a collection because the return type is a scalar. +<4> supporting methods follow the usual naming conventions. + (That said, in the case of properties, because the property is derived/read-only, the only supporting method that is relevant is `hideXxx()`). + + +== Contributed Action -The above example also omits any supporting methods, eg `hideXxx()`, `disableXxx()`, `validateXxx()`, etc. +Contributed properties are defined similarly, for example: -In the user interface the "documents" collection, the "add" and the "delete" actions will appear to be part of -`Customer`. In essence the framework constructs a composite UI from the parts of multiple objects. +[source,java] +---- +@Mixin +public class DocumentHolderAddDocument { + private final DocumentHolder holder; + public DocumentHolderDocuments(DocumentHolder holder) { this.holder = holder; } -[TIP] -==== -The (non-ASF) http://github.com/incodehq/incode-module-note[Incode note] and -http://github.com/incodehq/incode-module-commchannel[Incode commchannel] modules are real-world examples that use this -technique throughout. -==== + @Action() + @ActionLayout(contributed = Contributed.AS_ACTION) // <1> + public Document> addDocument(Document doc) { + ... + } + public boolean hideAddDocument() { ... } // <2> +} +---- +<1> recommended +<2> supporting methods follow the usual naming conventions. +== Inferred Name -== Contributing a single member +Where the mixin follows the naming convention `SomeType_mixinName` then the method name can be abbreviated to "$$". +The mixin name is everything after the last '_'. -The mixin can contribute as much or as little behaviour as makes sense. For example, in the example above it might be -that ``Document``s are created through some other mechanism (eg scanned) and are never deleted. In that case, the -mixin might be simply: +For example: [source,java] ---- @Mixin public class DocumentHolder_documents { - .. - public List<Document> documents() { ... } - ... + + private final DocumentHolder holder; + public DocumentHolder_documents(DocumentHolder holder) { this.holder = holder; } + + @Action(semantics=SemanticsOf.SAFE) + @ActionLayout(contributed = Contributed.AS_ASSOCIATION) + @CollectionLayout(render = RenderType.EAGERLY) + public List<Document> $$() { // <1> + ... + } + public boolean hide$$() { ... } // <2> } ---- +<1> using "$$" as the reserved method name +<2> supporting methods as usual + +As of `1.13.2-SNAPSHOT`, "$" is also recognized as a separator between the mixin type and mixin name. +This is useful for mixins implemented as nested static types, discussed below. + +== As Nested Static Classes -For the case where there is only a single member being contributed, the special name "__" (that is, two underscores) -can be used instead. In this case, the contributee member's name will be inferred from the mixin's class name. If the -class name itself contains an underscore, then the last part of the class name will be used. +As noted in the introduction, while mixins were originally introduced as a means of allowing contributions from one module to the types of another module, they are also a convenient mechanism for grouping functionality/behaviour against a concrete type. +All the methods and supporting methods end up in a single construct, and the dependency between that functionality and the rest of the object is made more explicit. -Thus, for a mixin whose class name is `DocumentHolder_documents`, the effective member name is `documents`. We could -therefore rewrite the mixin as: +When using mixins in this fashion, it is idiomatic to write the mixin as a nested static class, using the naming convention described above to reduce duplication. + +For example: [source,java] ---- -@Mixin -public class DocumentHolder_documents { - .. - public List<Document> __() { ... } - ... +public class Customer { + + @Mixin + public static class _placeOrder { // <1> + + private final Customer customer; + public documents(Customer customer) { this.customer = customer; } // <2> + + @Action + @ActionLayout(contributed = Contributed.AS_ACTION) + public List<Order> $$(Product p, int quantity) { // <3> + ... + } + public boolean hide$$() { ... } // <4> + public String validate0$$(Product p) { ... } + } } ---- +<1> must start with an "_" (the effective name of the class is `Customer$_placeOrder`. +<2> typically contributed to concrete class +<3> using the "$$" reserved name +<4> supporting methods as usual + -The benefit of this is marginal unless there are supporting methods, in which case the removal of boilerplate is welcome: +As of `1.13.2-SNAPSHOT`, the leading "_" can be omitted because "$" is also recognized as an identifier. +Moreover, the mixin class can be capitalized if desired. +Thus: [source,java] ---- -@Mixin -public class DocumentHolder_documents { - .. - public List<Document> __() { ... } - public boolean hide__() { ... } - public String disable__() { ... } - ... +public class Customer { + + @Mixin + public static class PlaceOrder { // <1> + + private final Customer customer; + public documents(Customer customer) { this.customer = customer; } // <2> + + @Action + @ActionLayout(contributed = Contributed.AS_ACTION) + public List<Order> $$(Product p, int quantity) { // <3> + ... + } + public boolean hide$$() { ... } // <4> + public String validate0$$(Product p) { ... } + } } ---- +In other words, all of the following are allowed (in `1.13.2-SNAPSHOT`): + +* `public static class Documents { ... }` +* `public static class documents { ... }` +* `public static class _Documents { ... }` +* `public static class _documents { ... }` + +(As of `1.13.2-SNAPSHOT`), the reserved method name "$$" can also be changed using xref:rgant.adoc#_rgant_Mixin_method[`@Mixin#method()`] or xref:rgant.adoc#_rgant_DomainObject_mixinMethod[`@DomainObject#mixinMethod()`]. + + + + + + + + == Programmatic usage When a domain object is rendered, the framework will automatically instantiate all required mixins and delegate to them http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java ---------------------------------------------------------------------- diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java index 5f68984..cf0cd58 100644 --- a/core/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java +++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/DomainObject.java @@ -156,6 +156,16 @@ public @interface DomainObject { Nature nature() default Nature.NOT_SPECIFIED; + + /** + * Equivalent to {@link Mixin#method()}. + * + * <p> + * Applicable only if {@link #nature()} is {@link Nature#MIXIN}. + * </p> + */ + String mixinMethod() default Mixin.DEFAULT_METHOD_NAME; + // ////////////////////////////////////// @@ -236,6 +246,4 @@ public @interface DomainObject { * </p> */ Class<? extends ObjectRemovingEvent<?>> removingLifecycleEvent() default ObjectRemovingEvent.Default.class; - - } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/applib/src/main/java/org/apache/isis/applib/annotation/Mixin.java ---------------------------------------------------------------------- diff --git a/core/applib/src/main/java/org/apache/isis/applib/annotation/Mixin.java b/core/applib/src/main/java/org/apache/isis/applib/annotation/Mixin.java index 7f4f646..7392063 100644 --- a/core/applib/src/main/java/org/apache/isis/applib/annotation/Mixin.java +++ b/core/applib/src/main/java/org/apache/isis/applib/annotation/Mixin.java @@ -34,5 +34,28 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) public @interface Mixin { + /** + * The default of {@link Mixin#method()}). + */ + String DEFAULT_METHOD_NAME = "$$"; + + /** + * Specifies the name of the verb to use within the mixin, eg "exec", "invoke", "apply" and so on, + * + * <p> + * This makes it easier to avoid silly spelling mistakes in supporting methods, with the name of the member + * in essence specified in only just one place, namely the mixin class' name. + * </p> + * + * <p> + * If not specified, then the default value {@link #DEFAULT_METHOD_NAME} is used instead. + * </p> + * + * <p> + * Remarks: originally intended to use a single (or perhaps two) underscore, however these may will not be + * valid identifiers after Java 8. + * </p> + */ + String method() default DEFAULT_METHOD_NAME; } http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacet.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacet.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacet.java index bce8da3..4bce13b 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacet.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacet.java @@ -22,7 +22,7 @@ package org.apache.isis.core.metamodel.facets.object.mixin; import org.apache.isis.applib.annotation.DomainObject; import org.apache.isis.applib.annotation.Nature; import org.apache.isis.core.metamodel.adapter.ObjectAdapter; -import org.apache.isis.core.metamodel.facetapi.Facet; +import org.apache.isis.core.metamodel.facets.SingleValueFacet; import org.apache.isis.core.metamodel.spec.ObjectSpecification; /** @@ -31,7 +31,7 @@ import org.apache.isis.core.metamodel.spec.ObjectSpecification; * {@link DomainObject#nature()} of {@link Nature#MIXIN}) and which have a 1-arg constructor accepting an object * (being the object this is a mix-in for). */ -public interface MixinFacet extends Facet { +public interface MixinFacet extends SingleValueFacet<String> { boolean isMixinFor(Class<?> candidateDomainType); @@ -49,4 +49,7 @@ public interface MixinFacet extends Facet { * Returns the mixin around the provided domain object */ Object instantiate(Object domainPojo); + + + } http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetAbstract.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetAbstract.java index 09fc8a0..b719f39 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetAbstract.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetAbstract.java @@ -28,10 +28,10 @@ import org.apache.isis.core.metamodel.adapter.ObjectAdapter; import org.apache.isis.core.metamodel.adapter.mgr.AdapterManager; import org.apache.isis.core.metamodel.facetapi.Facet; import org.apache.isis.core.metamodel.facetapi.FacetHolder; -import org.apache.isis.core.metamodel.facets.MarkerFacetAbstract; +import org.apache.isis.core.metamodel.facets.SingleValueFacetAbstract; import org.apache.isis.core.metamodel.services.ServicesInjector; -public abstract class MixinFacetAbstract extends MarkerFacetAbstract implements MixinFacet { +public abstract class MixinFacetAbstract extends SingleValueFacetAbstract<String> implements MixinFacet { private final Class<?> mixinType; private final Class<?> constructorType; @@ -43,10 +43,10 @@ public abstract class MixinFacetAbstract extends MarkerFacetAbstract implements public MixinFacetAbstract( final Class<?> mixinType, - final Class<?> constructorType, + final String value, final Class<?> constructorType, final FacetHolder holder, final ServicesInjector servicesInjector) { - super(type(), holder); + super(type(), value, holder); this.mixinType = mixinType; this.constructorType = constructorType; this.servicesInjector = servicesInjector; http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java index aac7d79..041d57a 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForDomainObjectAnnotation.java @@ -35,10 +35,10 @@ public class MixinFacetForDomainObjectAnnotation extends MixinFacetAbstract { private MixinFacetForDomainObjectAnnotation( final Class<?> mixinType, - final Class<?> constructorType, + final String value, final Class<?> constructorType, final FacetHolder holder, final ServicesInjector servicesInjector) { - super(mixinType, constructorType, holder, servicesInjector); + super(mixinType, value, constructorType, holder, servicesInjector); } public static MixinFacet create( @@ -58,7 +58,7 @@ public class MixinFacetForDomainObjectAnnotation extends MixinFacetAbstract { continue; } final Class<?> constructorType = constructorTypes[0]; - return new MixinFacetForDomainObjectAnnotation(candidateMixinType, constructorType, facetHolder, + return new MixinFacetForDomainObjectAnnotation(candidateMixinType, domainObject.mixinMethod(), constructorType, facetHolder, servicesInjector); } return null; http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java index a575ddf..d042eed 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/facets/object/mixin/MixinFacetForMixinAnnotation.java @@ -34,10 +34,10 @@ public class MixinFacetForMixinAnnotation extends MixinFacetAbstract { private MixinFacetForMixinAnnotation( final Class<?> mixinType, - final Class<?> constructorType, + final String value, final Class<?> constructorType, final FacetHolder holder, final ServicesInjector servicesInjector) { - super(mixinType, constructorType, holder, servicesInjector); + super(mixinType, value, constructorType, holder, servicesInjector); } public static MixinFacet create( @@ -54,7 +54,7 @@ public class MixinFacetForMixinAnnotation extends MixinFacetAbstract { continue; } final Class<?> constructorType = constructorTypes[0]; - return new MixinFacetForMixinAnnotation(candidateMixinType, constructorType, facetHolder, servicesInjector); + return new MixinFacetForMixinAnnotation(candidateMixinType, mixin.method(), constructorType, facetHolder, servicesInjector); } return null; } http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/MixedInMember.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/MixedInMember.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/MixedInMember.java index 7b8faf4..46795b1 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/MixedInMember.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/MixedInMember.java @@ -16,7 +16,7 @@ */ package org.apache.isis.core.metamodel.specloader.specimpl; -import org.apache.isis.core.metamodel.spec.ObjectSpecification; +import org.apache.isis.applib.annotation.Mixin; import org.apache.isis.core.metamodel.spec.feature.ObjectMember; /** @@ -25,23 +25,7 @@ import org.apache.isis.core.metamodel.spec.feature.ObjectMember; public interface MixedInMember extends ObjectMember { /** - * If the mixin uses a method of precisely this name, then the corresponding {@link ObjectMember#getName() name} and - * {@link ObjectMember#getId() id} will instead be inferred from the mixin class' {@link ObjectSpecification#getShortIdentifier() name}. - * - * <p> - * This makes it easier to avoid silly spelling mistakes in supporting methods, with the name of the member - * in essence specified in only just one place, namely the mixin class' name. - * </p> - * - * <p> - * Remarks: originally intended to use a single (or perhaps two) underscore, however these may not be valid - * identifiers after Java 8. - * </p> - */ - public static final String DEFAULT_MEMBER_NAME = "$$"; - - /** - * The id if it was originally {@link #DEFAULT_MEMBER_NAME the default member name}. + * The id if it was originally {@link Mixin#DEFAULT_METHOD_NAME the default member name}. */ String getOriginalId(); http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java index 96bd8ea..752ffaa 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectActionMixedIn.java @@ -18,7 +18,6 @@ package org.apache.isis.core.metamodel.specloader.specimpl; import java.util.List; -import com.google.common.base.Objects; import com.google.common.base.Strings; import com.google.common.collect.Lists; @@ -72,6 +71,7 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM public ObjectActionMixedIn( final Class<?> mixinType, + final String mixinMethodName, final ObjectActionDefault mixinAction, final ObjectSpecification mixedInType, final ServicesInjector objectMemberDependencies) { @@ -87,7 +87,7 @@ public class ObjectActionMixedIn extends ObjectActionDefault implements MixedInM // adjust name if necessary final String name = getName(); - if(Strings.isNullOrEmpty(name) || Objects.equal(name, DEFAULT_MEMBER_NAME)) { + if(Strings.isNullOrEmpty(name) || name.equalsIgnoreCase(mixinMethodName)) { String memberName = determineNameFrom(mixinAction); FacetUtil.addFacet(new NamedFacetInferred(memberName, facetHolder)); } http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java index d45479f..3d7dab1 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectMemberAbstract.java @@ -20,8 +20,7 @@ package org.apache.isis.core.metamodel.specloader.specimpl; import java.util.List; - -import com.google.common.base.Objects; +import java.util.Objects; import org.apache.isis.applib.Identifier; import org.apache.isis.applib.annotation.When; @@ -335,7 +334,7 @@ public abstract class ObjectMemberAbstract implements ObjectMember { } static String determineIdFrom(final ObjectActionDefault mixinAction) { - final String id = compress(suffix(mixinAction)); + final String id = StringExtensions.asCamelLowerFirst(compress(suffix(mixinAction))); return id; } @@ -348,17 +347,26 @@ public abstract class ObjectMemberAbstract implements ObjectMember { } static String suffix(final String singularName) { - if (singularName.endsWith("_")) { - if (Objects.equal(singularName, "_")) { - return singularName; - } - return singularName; + final String deriveFromUnderscore = derive(singularName, "_"); + if(!Objects.equals(singularName, deriveFromUnderscore)) { + return deriveFromUnderscore; } - final int indexOfUnderscore = singularName.lastIndexOf('_'); - if (indexOfUnderscore == -1) { - return singularName; + final String deriveFromDollar = derive(singularName, "$"); + if(!Objects.equals(singularName, deriveFromDollar)) { + return deriveFromDollar; } - return singularName.substring(indexOfUnderscore + 1); + return singularName; + } + + private static String derive(final String singularName, final String separator) { + final int indexOfSeparator = singularName.lastIndexOf(separator); + return occursNotAtEnd(singularName, indexOfSeparator) + ? singularName.substring(indexOfSeparator + 1) + : singularName; + } + + private static boolean occursNotAtEnd(final String singularName, final int indexOfUnderscore) { + return indexOfUnderscore != -1 && indexOfUnderscore != singularName.length() - 1; } //endregion http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java index 52cc112..808c3f0 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/ObjectSpecificationAbstract.java @@ -994,7 +994,7 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem return true; } }), - createMixedInAssociationFunctor(this, mixinType) + createMixedInAssociationFunctor(this, mixinType, mixinFacet.value()) )); toAppendTo.addAll(mixedInAssociations); @@ -1006,7 +1006,8 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem private Function<ObjectActionDefault, ObjectAssociation> createMixedInAssociationFunctor( final ObjectSpecification mixedInType, - final Class<?> mixinType) { + final Class<?> mixinType, + final String mixinMethodName) { return new Function<ObjectActionDefault, ObjectAssociation>(){ @Override public ObjectAssociation apply(final ObjectActionDefault mixinAction) { @@ -1020,10 +1021,10 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem final ObjectSpecification returnType = mixinAction.getReturnType(); if (returnType.isNotCollection()) { return new OneToOneAssociationMixedIn( - mixinAction, mixedInType, mixinType, servicesInjector); + mixinAction, mixedInType, mixinType, mixinMethodName, servicesInjector); } else { return new OneToManyAssociationMixedIn( - mixinAction, mixedInType, mixinType, servicesInjector); + mixinAction, mixedInType, mixinType, mixinMethodName, servicesInjector); } } }; @@ -1137,11 +1138,12 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem private void addMixedInActionsIfAny( final Class<?> mixinType, final List<ObjectAction> mixedInActionsToAppendTo) { - final ObjectSpecification specification = getSpecificationLoader().loadSpecification(mixinType); - if (specification == this) { + + final ObjectSpecification mixinSpec = getSpecificationLoader().loadSpecification(mixinType); + if (mixinSpec == this) { return; } - final MixinFacet mixinFacet = specification.getFacet(MixinFacet.class); + final MixinFacet mixinFacet = mixinSpec.getFacet(MixinFacet.class); if(mixinFacet == null) { // this shouldn't happen; perhaps it would be more correct to throw an exception? return; @@ -1151,7 +1153,7 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem } final List<ObjectAction> actions = Lists.newArrayList(); - final List<ObjectAction> mixinActions = specification.getObjectActions(ActionType.ALL, Contributed.INCLUDED, Filters + final List<ObjectAction> mixinActions = mixinSpec.getObjectActions(ActionType.ALL, Contributed.INCLUDED, Filters .<ObjectAction>any()); for (final ObjectAction mixinTypeAction : mixinActions) { if (isAlwaysHidden(mixinTypeAction)) { @@ -1167,7 +1169,7 @@ public abstract class ObjectSpecificationAbstract extends FacetHolderImpl implem } ObjectActionMixedIn mixedInAction = - new ObjectActionMixedIn(mixinType, mixinAction, this, servicesInjector); + new ObjectActionMixedIn(mixinType, mixinFacet.value(), mixinAction, this, servicesInjector); facetProcessor.processMemberOrder(metadataProperties, mixedInAction); actions.add(mixedInAction); } http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java index 0e66c97..d82e7d5 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToManyAssociationMixedIn.java @@ -18,7 +18,6 @@ package org.apache.isis.core.metamodel.specloader.specimpl; import java.util.List; -import com.google.common.base.Objects; import com.google.common.base.Strings; import org.apache.isis.applib.Identifier; @@ -87,6 +86,7 @@ public class OneToManyAssociationMixedIn extends OneToManyAssociationDefault imp final ObjectActionDefault mixinAction, final ObjectSpecification mixedInType, final Class<?> mixinType, + final String mixinMethodName, final ServicesInjector servicesInjector) { super(mixinAction.getFacetedMethod(), typeOfSpec(mixinAction, servicesInjector), @@ -120,7 +120,7 @@ public class OneToManyAssociationMixedIn extends OneToManyAssociationDefault imp // adjust name if necessary final String name = getName(); - if(Strings.isNullOrEmpty(name) || Objects.equal(name, DEFAULT_MEMBER_NAME)) { + if(Strings.isNullOrEmpty(name) || name.equalsIgnoreCase(mixinMethodName)) { String memberName = ObjectActionMixedIn.determineNameFrom(mixinAction); FacetUtil.addFacet(new NamedFacetInferred(memberName, facetHolder)); } http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java ---------------------------------------------------------------------- diff --git a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java index e48a44d..668465e 100644 --- a/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java +++ b/core/metamodel/src/main/java/org/apache/isis/core/metamodel/specloader/specimpl/OneToOneAssociationMixedIn.java @@ -18,7 +18,6 @@ package org.apache.isis.core.metamodel.specloader.specimpl; import java.util.List; -import com.google.common.base.Objects; import com.google.common.base.Strings; import org.apache.isis.applib.Identifier; @@ -72,6 +71,7 @@ public class OneToOneAssociationMixedIn extends OneToOneAssociationDefault imple final ObjectActionDefault mixinAction, final ObjectSpecification mixedInType, final Class<?> mixinType, + final String mixinMethodName, final ServicesInjector servicesInjector) { super(mixinAction.getFacetedMethod(), mixinAction.getReturnType(), servicesInjector); @@ -99,7 +99,7 @@ public class OneToOneAssociationMixedIn extends OneToOneAssociationDefault imple // adjust name if necessary final String name = getName(); - if(Strings.isNullOrEmpty(name) || Objects.equal(name, DEFAULT_MEMBER_NAME)) { + if(Strings.isNullOrEmpty(name) || name.equalsIgnoreCase(mixinMethodName)) { String memberName = ObjectActionMixedIn.determineNameFrom(mixinAction); FacetUtil.addFacet(new NamedFacetInferred(memberName, facetHolder)); } http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/example/application/simpleapp/application/src/test/java/domainapp/application/integtests/Smoke_IntegTest.java ---------------------------------------------------------------------- diff --git a/example/application/simpleapp/application/src/test/java/domainapp/application/integtests/Smoke_IntegTest.java b/example/application/simpleapp/application/src/test/java/domainapp/application/integtests/Smoke_IntegTest.java index fb9c12c..4b514e8 100644 --- a/example/application/simpleapp/application/src/test/java/domainapp/application/integtests/Smoke_IntegTest.java +++ b/example/application/simpleapp/application/src/test/java/domainapp/application/integtests/Smoke_IntegTest.java @@ -42,7 +42,7 @@ public class Smoke_IntegTest extends DomainAppIntegTestAbstract { SimpleObjectMenu menu; @Test - public void create_() throws Exception { + public void create() throws Exception { // given DomainAppTearDown fs = new DomainAppTearDown(); @@ -81,7 +81,7 @@ public class Smoke_IntegTest extends DomainAppIntegTestAbstract { // when - wrap(mixin(SimpleObject._updateName.class, fred)).$$("Freddy"); + wrap(mixin(SimpleObject.updateName.class, fred)).exec("Freddy"); transactionService.flushTransaction(); // then @@ -97,7 +97,7 @@ public class Smoke_IntegTest extends DomainAppIntegTestAbstract { // when - wrap(mixin(SimpleObject._delete.class, fred)).$$(); + wrap(mixin(SimpleObject.delete.class, fred)).exec(); transactionService.flushTransaction(); http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java ---------------------------------------------------------------------- diff --git a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java index da27e46..23b3c54 100644 --- a/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java +++ b/example/application/simpleapp/module-simple/src/main/java/domainapp/modules/simple/dom/impl/SimpleObject.java @@ -140,15 +140,15 @@ public class SimpleObject implements Comparable<SimpleObject> { //endregion //region > updateName (action) - @Mixin - public static class _updateName { + @Mixin(method = "exec") + public static class updateName { public static class ActionDomainEvent extends SimpleModuleDomSubmodule.ActionDomainEvent<SimpleObject> { } private final SimpleObject simpleObject; - public _updateName(final SimpleObject simpleObject) { + public updateName(final SimpleObject simpleObject) { this.simpleObject = simpleObject; } @@ -161,7 +161,7 @@ public class SimpleObject implements Comparable<SimpleObject> { @ActionLayout( contributed = Contributed.AS_ACTION ) - public SimpleObject $$( + public SimpleObject exec( @Parameter(maxLength = SimpleObject.NameType.Meta.MAX_LEN) @ParameterLayout(named = "Name") final String name) { @@ -169,11 +169,11 @@ public class SimpleObject implements Comparable<SimpleObject> { return simpleObject; } - public String default0$$() { + public String default0Exec() { return simpleObject.getName(); } - public TranslatableString validate0$$(final String name) { + public TranslatableString validate0Exec(final String name) { return name != null && name.contains("!") ? TranslatableString.tr("Exclamation mark is not allowed") : null; } @@ -181,14 +181,14 @@ public class SimpleObject implements Comparable<SimpleObject> { //endregion //region > delete (action) - @Mixin - public static class _delete { + @Mixin(method = "exec") + public static class delete { public static class ActionDomainEvent extends SimpleModuleDomSubmodule.ActionDomainEvent<SimpleObject> { } private final SimpleObject simpleObject; - public _delete(final SimpleObject simpleObject) { + public delete(final SimpleObject simpleObject) { this.simpleObject = simpleObject; } @@ -199,7 +199,7 @@ public class SimpleObject implements Comparable<SimpleObject> { @ActionLayout( contributed = Contributed.AS_ACTION ) - public void $$() { + public void exec() { final String title = titleService.titleOf(simpleObject); messageService.informUser(String.format("'%s' deleted", title)); repositoryService.remove(simpleObject); http://git-wip-us.apache.org/repos/asf/isis/blob/147f4c5d/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObject_IntegTest.java ---------------------------------------------------------------------- diff --git a/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObject_IntegTest.java b/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObject_IntegTest.java index 29d0bba..f6ac63e 100644 --- a/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObject_IntegTest.java +++ b/example/application/simpleapp/module-simple/src/test/java/domainapp/modules/simple/integtests/tests/SimpleObject_IntegTest.java @@ -87,7 +87,7 @@ public class SimpleObject_IntegTest extends SimpleModuleIntegTestAbstract { public void can_be_updated_directly() throws Exception { // when - wrap(mixin(SimpleObject._updateName.class, simpleObject)).$$("new name"); + wrap(mixin(SimpleObject.updateName.class, simpleObject)).exec("new name"); transactionService.nextTransaction(); // then @@ -102,7 +102,7 @@ public class SimpleObject_IntegTest extends SimpleModuleIntegTestAbstract { expectedExceptions.expectMessage("Exclamation mark is not allowed"); // when - wrap(mixin(SimpleObject._updateName.class, simpleObject)).$$("new name!"); + wrap(mixin(SimpleObject.updateName.class, simpleObject)).exec("new name!"); } }