This is an automated email from the ASF dual-hosted git repository. danhaywood pushed a commit to branch CAUSEWAY-2485 in repository https://gitbox.apache.org/repos/asf/causeway.git
commit a477d7515f7f257e3bb0788cf701d8cb9507e9eb Author: danhaywood <[email protected]> AuthorDate: Thu May 11 07:34:52 2023 +0100 CAUSEWAY-2485: adds example of scalar value type --- .../ComplexNumberValueSemantics.java | 37 +++-- .../CompositeValueTypePage-description.adoc | 42 +++--- .../progmodel/customvalues/EmailAddress.java | 29 ++++ .../customvalues/EmailAddressValueSemantics.java | 154 +++++++++++++++++++++ .../objects/progmodel/customvalues/Percentage.java | 29 ++++ .../customvalues/ScalarValueTypeMenu.java | 48 +++++++ .../ScalarValueTypePage-description.adoc | 104 ++++++++++++++ .../customvalues/ScalarValueTypePage.java | 50 +++++++ .../customvalues/ScalarValueTypePage.layout.xml | 60 ++++++++ .../src/main/java/demoapp/dom/menubars.layout.xml | 1 + .../src/main/resources/static/css/application.css | 2 +- 11 files changed, 519 insertions(+), 37 deletions(-) diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/compositevalues/ComplexNumberValueSemantics.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/compositevalues/ComplexNumberValueSemantics.java index 9a259a458e..3d61644b25 100644 --- a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/compositevalues/ComplexNumberValueSemantics.java +++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/compositevalues/ComplexNumberValueSemantics.java @@ -21,7 +21,6 @@ package demoapp.dom.domain.objects.progmodel.compositevalues; import javax.inject.Named; import org.springframework.context.annotation.Import; -import org.springframework.context.annotation.Profile; import org.springframework.stereotype.Component; import org.apache.causeway.applib.util.schema.CommonDtoUtils; @@ -51,13 +50,6 @@ public class ComplexNumberValueSemantics return ValueType.COMPOSITE; } -// tag::getDefaultsProvider[] - @Override - public DefaultsProvider<ComplexNumber> getDefaultsProvider() { - return ()-> ComplexNumber.of(0, 0); - } -// end::getDefaultsProvider[] - // tag::compose[] @Override public ValueDecomposition decompose(final ComplexNumber value) { @@ -78,21 +70,28 @@ public class ComplexNumberValueSemantics } // end::compose[] -// tag::getRenderer[] +// tag::getDefaultsProvider[] @Override - public Renderer<ComplexNumber> getRenderer() { - return (context, object) -> title(object, "NaN"); + public DefaultsProvider<ComplexNumber> getDefaultsProvider() { + return ()-> ComplexNumber.of(0, 0); } +// end::getDefaultsProvider[] - private static String title(ComplexNumber complexNumber, final String fallbackIfNull) { - if (complexNumber == null) return fallbackIfNull; - return complexNumber.getRe() + - (complexNumber.getIm() >= 0 - ? (" + " + complexNumber.getIm()) - : (" - " + (-complexNumber.getIm()))) - + "i"; +// tag::getRenderer[] + @Override + public Renderer<ComplexNumber> getRenderer() { + return new Renderer<>() { + @Override + public String titlePresentation(Context context, ComplexNumber object) { + if (object == null) return "NaN"; + return object.getRe() + + (object.getIm() >= 0 + ? (" + " + object.getIm()) + : (" - " + (-object.getIm()))) + + "i"; + } + }; } - // end::getRenderer[] // tag::class[] diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/compositevalues/CompositeValueTypePage-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/compositevalues/CompositeValueTypePage-description.adoc index 5094cdf96a..012bb58185 100644 --- a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/compositevalues/CompositeValueTypePage-description.adoc +++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/compositevalues/CompositeValueTypePage-description.adoc @@ -8,7 +8,8 @@ Value types are distinct from "entity types," which represent objects with a uni In contrast, value types have no identity of their own, and two value objects with the same values are considered equal. It's also common for value types to define an algebra, where they can be combined through operations to produce new values. -A composite value type has more than one data attribute. +A scalar value type has a single data attribute, while a composite value type has multiple. +This page demonstrates the use of *composite* value types. == How this demo works @@ -57,46 +58,47 @@ WARNING: the framework currently has a bug in that it doesn't prevent the end-us + The action to subtract is similar. +=== Value Semantics Provider + The framework also needs to know the structure of the value type. This is done by providing an implementation of a link:https://causeway.apache.org/refguide/2.0.0-RC1/applib/index/value/semantics/ValueSemanticsProvider.html[ValueSemanticsProvider]. * the `ValueSemanticsProvider` implementation is: + -[source,java] +[source,java,indent=0] .ComplexNumberValueSemantics.java ---- include::ComplexNumberValueSemantics.java[tags=class] ---- -<.> declares a mixin that the framework uses to present an action prompt to set the parts of the value type. +<.> declares a "default" mixin that the framework uses to present an action prompt to set the parts of the value type. This is discussed in more detail below. <.> inherits from link:https://causeway.apache.org/refguide/2.0.0-RC1/applib/index/value/semantics/ValueSemanticsAbstract.html[ValueSemanticsAbstract], a convenience adapter. -* its implementation of `getDefaultsProvider()` is: +* the `compose()` and `decompose()` methods are used to serialize the object using the structures defined by the link:https://causeway.apache.org/refguide/2.0.0-RC1/schema/about.html[XSD schemas]. + -[source,java] -.ComplexNumberValueSemantics.java ----- -include::ComplexNumberValueSemantics.java[tags=getDefaultsProvider] ----- - -* its implementation of `compose()` and `decompose()` is: +Using this, the framework can render the composite value as JSON (as used by the REST API), or to XML, as used by SPIs such as link:https://causeway.apache.org/refguide/2.0.0-RC1/applib/index/services/publishing/spi/CommandSubscriber.html#section-top[CommandSubscriber] (see link:https://causeway.apache.org/refguide/2.0.0-RC1/applib/index/services/command/Command.html[Command] and link:https://causeway.apache.org/refguide/2.0.0-RC1/schema/cmd.html[CommandDto]). + -[source,java] -.ComplexNumberValueSemantics.java +[source,java,indent=0] ---- include::ComplexNumberValueSemantics.java[tags=compose] ---- -* its implementation of `getRenderer()` is: +* the `getRenderer()` is used to render the value as a string. +An HTML representation can also be provided, though this type doesn't warrant one. + -[source,java] -.ComplexNumberValueSemantics.java +[source,java,indent=0] ---- include::ComplexNumberValueSemantics.java[tags=getRenderer] ---- -* As noted above, the "default" mixin defines an action to set the parts of the value type. +* the `getDefaultsProvider()` provides an initial value (eg non-nullable properties): + +[source,java,indent=0] +---- +include::ComplexNumberValueSemantics.java[tags=getDefaultsProvider] +---- + +* Finally, the "default" mixin (mentioned above) defines an action to set the components of the value type. The name "default" in this context is in effect a reserved method name. + [source,java] @@ -106,4 +108,10 @@ include::ComplexNumber_default.java[tags=default-mixin] ---- <.> should always specify the `INLINE_AS_IF_EDIT` prompt style, because the prompt may be "nested" within an outer action prompt (e.g. the `addComplexNumber` action of the page object iself) +Comparing composite value types to scalar value types, you'll notice that a composite type doesn't need to define a `Parser` implementation; instead the "default" mixin performs an equivalent role. + +=== Integrating with an ORM + +Be aware that if using the value type within an entity, then it will also be necessary to implement additional code to instruct the ORM how to convert the value type into the database. +The "embedded types" demo page shows how this can be done. diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/EmailAddress.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/EmailAddress.java new file mode 100644 index 0000000000..f67333b673 --- /dev/null +++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/EmailAddress.java @@ -0,0 +1,29 @@ +/* + * 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. + */ +package demoapp.dom.domain.objects.progmodel.customvalues; + + +// tag::class[] [email protected] // <.> [email protected] // <.> [email protected](staticName = "of") +public class EmailAddress { + String emailAddress; // <.> +} +// end::class[] diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/EmailAddressValueSemantics.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/EmailAddressValueSemantics.java new file mode 100644 index 0000000000..1e639613b3 --- /dev/null +++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/EmailAddressValueSemantics.java @@ -0,0 +1,154 @@ +/* + * 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. + */ +package demoapp.dom.domain.objects.progmodel.customvalues; + +import lombok.NonNull; + +import java.util.regex.Pattern; + +import javax.inject.Named; + +import org.apache.causeway.applib.services.bookmark.IdStringifier; +import org.apache.causeway.applib.value.semantics.Parser; +import org.apache.causeway.commons.internal.base._Strings; +import org.apache.causeway.schema.common.v2.ValueWithTypeDto; + +import org.springframework.stereotype.Component; + +import org.apache.causeway.applib.value.semantics.DefaultsProvider; +import org.apache.causeway.applib.value.semantics.Renderer; +import org.apache.causeway.applib.value.semantics.ValueDecomposition; +import org.apache.causeway.applib.value.semantics.ValueSemanticsAbstract; +import org.apache.causeway.schema.common.v2.ValueType; + +// tag::class[] +@Named("demo.EmailAddressValueSemantics") +@Component +public class EmailAddressValueSemantics + extends ValueSemanticsAbstract<EmailAddress> { // <.> + // ... +// end::class[] + + @Override + public Class<EmailAddress> getCorrespondingClass() { + return EmailAddress.class; + } + + @Override + public ValueType getSchemaValueType() { + return ValueType.STRING; + } + +// tag::compose[] + @Override + public ValueDecomposition decompose(final EmailAddress value) { + return decomposeAsNullable(value, EmailAddress::getEmailAddress, ()->null); + } + + @Override + public EmailAddress compose(final ValueDecomposition decomposition) { + return composeFromNullable( + decomposition, ValueWithTypeDto::getString, EmailAddress::of, ()->null); + } +// end::compose[] + +// tag::getDefaultsProvider[] + @Override + public DefaultsProvider<EmailAddress> getDefaultsProvider() { + return new DefaultsProvider<EmailAddress>() { + @Override + public EmailAddress getDefaultValue() { + return EmailAddress.of(""); + } + }; + } +// end::getDefaultsProvider[] + +// tag::getRenderer[] + @Override + public Renderer<EmailAddress> getRenderer() { + return new Renderer<>() { + @Override + public String titlePresentation(Context context, EmailAddress emailAddress) { + return emailAddress == null ? null : emailAddress.getEmailAddress(); + } + }; + } + +// end::getRenderer[] + +// tag::getParser[] + @Override + public Parser<EmailAddress> getParser() { + return new Parser<>() { + // https://stackoverflow.com/a/47181151 + final Pattern REGEX = Pattern.compile("^[\\w-\\+]+(\\.[\\w]+)*@[\\w-]+(\\.[\\w]+)*(\\.[a-zA-Z]{2,})$"); + + @Override + public String parseableTextRepresentation(Context context, EmailAddress value) { + return renderTitle(value, EmailAddress::getEmailAddress); + } + + @Override + public EmailAddress parseTextRepresentation(Context context, String text) { + if(!REGEX.matcher(text).matches()) { + throw new RuntimeException("Invalid email format"); + } + if (_Strings.isEmpty(text)) return null; + return EmailAddress.of(text); + } + + @Override + public int typicalLength() { + return 20; + } + + @Override + public int maxLength() { + return 50; + } + }; + } +// end::getParser[] + +// tag::getIdStringifier[] + @Override + public IdStringifier<EmailAddress> getIdStringifier() { + return new IdStringifier.EntityAgnostic<>() { + @Override + public Class<EmailAddress> getCorrespondingClass() { + return EmailAddressValueSemantics.this.getCorrespondingClass(); + } + + @Override + public String enstring(@NonNull EmailAddress value) { + return _Strings.base64UrlEncode(value.getEmailAddress()); + } + + @Override + public EmailAddress destring(@NonNull String stringified) { + return EmailAddress.of(_Strings.base64UrlDecode(stringified)); + } + }; + } +// end::getIdStringifier[] + +// tag::class[] +} +// end::class[] diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/Percentage.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/Percentage.java new file mode 100644 index 0000000000..883bf94322 --- /dev/null +++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/Percentage.java @@ -0,0 +1,29 @@ +/* + * 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. + */ +package demoapp.dom.domain.objects.progmodel.customvalues; + + +// tag::class[] [email protected] // <.> [email protected] // <.> [email protected](staticName = "of") +public class Percentage { + int percentage; // <.> +} +// end::class[] diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypeMenu.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypeMenu.java new file mode 100644 index 0000000000..ad454dcabb --- /dev/null +++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypeMenu.java @@ -0,0 +1,48 @@ +/* + * 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. + */ +package demoapp.dom.domain.objects.progmodel.customvalues; + +import javax.inject.Inject; +import javax.inject.Named; + +import org.apache.causeway.applib.annotation.Action; +import org.apache.causeway.applib.annotation.ActionLayout; +import org.apache.causeway.applib.annotation.DomainService; +import org.apache.causeway.applib.annotation.NatureOfService; +import org.apache.causeway.applib.annotation.PriorityPrecedence; +import org.apache.causeway.applib.services.factory.FactoryService; + +import lombok.RequiredArgsConstructor; + +@Named("demo.ScalarValueTypeMenu") +@DomainService(nature=NatureOfService.VIEW) [email protected](PriorityPrecedence.EARLY) +@RequiredArgsConstructor(onConstructor_ = {@Inject}) +public class ScalarValueTypeMenu { + + private final FactoryService factoryService; + + @Action + @ActionLayout(cssClassFa="fa-cubes", describedAs = "Custom scalar value types") + public ScalarValueTypePage scalarValueTypes(){ + ScalarValueTypePage page = factoryService.viewModel(new ScalarValueTypePage()); + page.setEmailAddress(EmailAddress.of("[email protected]")); + return page; + } +} diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypePage-description.adoc b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypePage-description.adoc new file mode 100644 index 0000000000..768c054992 --- /dev/null +++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypePage-description.adoc @@ -0,0 +1,104 @@ +: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 ag [...] + + +"Value types" represent concepts that have intrinsic value and are immutable. +They are often used to model concepts such as money, dates, addresses, and other types of measurements or quantities that have a specific value. + +Value types are distinct from "entity types," which represent objects with a unique identity that can change over time. +In contrast, value types have no identity of their own, and two value objects with the same values are considered equal. +It's also common for value types to define an algebra, where they can be combined through operations to produce new values. + +A scalar value type has a single data attribute, while a composite value type has multiple. +This page demonstrates the use of *scalar* value types. + + +== How this demo works + +This page object defines a single property whose type is a value type, `EmailAddress`. +This is in essence a string, but with an additional constraint (a regex) as to the formatting of that string. + +In terms of code: + +* The `EmailAddress` type is defined as: ++ +[source,java] +.EmailAddress.java +---- +include::EmailAddress.java[tags=class] +---- +<.> Defines this as a value type to the framework +<.> Uses lombok to define getters, a `hashCode()`, `equals()`, `toString()` and a constructor. +<.> The single data attribute + +* this page object defines this as a single property: ++ +[source,java] +.ScalarValueTypePage.java +---- +include::ScalarValueTypePage.java[tags=class] +---- + +=== Value Semantics Provider + +The framework also needs to know the structure of the value type. +This is done by providing an implementation of a link:https://causeway.apache.org/refguide/2.0.0-RC1/applib/index/value/semantics/ValueSemanticsProvider.html[ValueSemanticsProvider]. + +* the `ValueSemanticsProvider` implementation is: ++ +[source,java,indent=0] +.EmailAddressValueSemantics.java +---- +include::EmailAddressValueSemantics.java[tags=class] +---- +<.> inherits from link:https://causeway.apache.org/refguide/2.0.0-RC1/applib/index/value/semantics/ValueSemanticsAbstract.html[ValueSemanticsAbstract], a convenience adapter. + +* the `compose()` and `decompose()` methods are used to serialize the object using the structures defined by the link:https://causeway.apache.org/refguide/2.0.0-RC1/schema/about.html[XSD schemas]. ++ +Using this, the framework can render the composite value as JSON (as used by the REST API), or to XML, as used by SPIs such as link:https://causeway.apache.org/refguide/2.0.0-RC1/applib/index/services/publishing/spi/CommandSubscriber.html#section-top[CommandSubscriber] (see link:https://causeway.apache.org/refguide/2.0.0-RC1/applib/index/services/command/Command.html[Command] and link:https://causeway.apache.org/refguide/2.0.0-RC1/schema/cmd.html[CommandDto]). ++ +[source,java,indent=0] +---- +include::EmailAddressValueSemantics.java[tags=compose] +---- + +* the `getRenderer()` is used to render the value as a string. +An HTML representation can also be provided, though this type doesn't warrant one. ++ +[source,java,indent=0] +---- +include::EmailAddressValueSemantics.java[tags=getRenderer] +---- + +* the `getDefaultsProvider()` provides an initial value (eg non-nullable properties): ++ +[source,java,indent=0] +---- +include::EmailAddressValueSemantics.java[tags=getDefaultsProvider] +---- + +* the `getParser()` is used to convert the string (entered in the UI) into the value type. +If the value entered is invalid, then an exception can be thrown. ++ +[source,java,indent=0] +---- +include::EmailAddressValueSemantics.java[tags=getParser] +---- + +* the `getIdStringifier()` allows the value type to be used as (part of) an identifier of the object. +The string returned must be URL safe. ++ +[source,java,indent=0] +---- +include::EmailAddressValueSemantics.java[tags=getIdStringifier] +---- + +Comparing scalar value types to composite value types, you'll notice that a scalar type doesn't need to define a "default" mixin; instead the `Parser` performs an equivalent role. + + +=== Integrating with an ORM + +Be aware that if using the value type within an entity, then it will also be necessary to implement additional code to instruct the ORM how to convert the value type into the database. +The ORMs offer several alternatives, but for example: + +* if using JPA, then implement `javax.persistence.AttributeConverter` +* if using JDO, then implement `org.datanucleus.store.types.converters.TypeConverter` diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypePage.java b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypePage.java new file mode 100644 index 0000000000..9b44327cf2 --- /dev/null +++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypePage.java @@ -0,0 +1,50 @@ +/* + * 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. + */ +package demoapp.dom.domain.objects.progmodel.customvalues; + +import javax.inject.Named; + +import org.apache.causeway.applib.annotation.DomainObject; +import org.apache.causeway.applib.annotation.Editing; +import org.apache.causeway.applib.annotation.Nature; +import org.apache.causeway.applib.annotation.ObjectSupport; +import org.apache.causeway.applib.annotation.Property; + +import lombok.Getter; +import lombok.Setter; + +import demoapp.dom._infra.asciidocdesc.HasAsciiDocDescription; + +// tag::class[] +@Named("demo.ScalarValueTypePage") +@DomainObject(nature=Nature.VIEW_MODEL) +public class ScalarValueTypePage implements HasAsciiDocDescription { + // ... +// end::class[] + @ObjectSupport public String title() { + return "Scalar Value Types"; + } + + +// tag::class[] + @Property(editing = Editing.ENABLED) + @Getter @Setter + private EmailAddress emailAddress; +} +// end::class[] diff --git a/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypePage.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypePage.layout.xml new file mode 100644 index 0000000000..d0a2776b2b --- /dev/null +++ b/examples/demo/domain/src/main/java/demoapp/dom/domain/objects/progmodel/customvalues/ScalarValueTypePage.layout.xml @@ -0,0 +1,60 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?> +<!-- 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. --> +<bs3:grid + xsi:schemaLocation="https://causeway.apache.org/applib/layout/component https://causeway.apache.org/applib/layout/component/component.xsd https://causeway.apache.org/applib/layout/grid/bootstrap3 https://causeway.apache.org/applib/layout/grid/bootstrap3/bootstrap3.xsd" + xmlns:bs3="https://causeway.apache.org/applib/layout/grid/bootstrap3" + xmlns:cpt="https://causeway.apache.org/applib/layout/component" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> + <bs3:row> + <bs3:col span="10" unreferencedActions="true"> + <cpt:domainObject/> + </bs3:col> + <bs3:col span="2"> + <cpt:fieldSet name="" id="sources" /> + </bs3:col> + </bs3:row> + <bs3:row> + <bs3:col span="6"> + <bs3:row> + <bs3:col span="12"> + <cpt:fieldSet name="General" id="general"> + <cpt:property id="emailAddress"/> + </cpt:fieldSet> + </bs3:col> + </bs3:row> + <bs3:row> + <bs3:col span="12"> + <cpt:fieldSet name="Other" id="other" unreferencedProperties="true"/> + </bs3:col> + </bs3:row> + </bs3:col> + <bs3:col span="6"> + <cpt:fieldSet name="Description" id="description"> + <cpt:action id="clearHints" position="PANEL" /> + <cpt:action id="rebuildMetamodel" position="PANEL"/> + <cpt:action id="downloadLayout" position="PANEL_DROPDOWN"/> + <cpt:action id="inspectMetamodel" position="PANEL_DROPDOWN"/> + <cpt:action id="downloadMetamodelXml" position="PANEL_DROPDOWN"/> + <cpt:action id="downloadJdoMetamodel" position="PANEL_DROPDOWN"/> + <cpt:action id="recentCommands" position="PANEL_DROPDOWN"/> + <cpt:action id="recentExecutions" position="PANEL_DROPDOWN"/> + <cpt:action id="recentAuditTrailEntries" position="PANEL_DROPDOWN"/> + <cpt:action id="impersonateWithRoles" position="PANEL_DROPDOWN"/> + <cpt:action id="openRestApi" position="PANEL_DROPDOWN" /> + <cpt:property id="description"/> + </cpt:fieldSet> + </bs3:col> + </bs3:row> + <bs3:row> + <bs3:col span="12" unreferencedCollections="true"/> + </bs3:row> +</bs3:grid> diff --git a/examples/demo/domain/src/main/java/demoapp/dom/menubars.layout.xml b/examples/demo/domain/src/main/java/demoapp/dom/menubars.layout.xml index 1fbb3e3c0c..e7e24639ad 100644 --- a/examples/demo/domain/src/main/java/demoapp/dom/menubars.layout.xml +++ b/examples/demo/domain/src/main/java/demoapp/dom/menubars.layout.xml @@ -52,6 +52,7 @@ For latest we use: https://raw.githubusercontent.com/apache/causeway/master/anto <mb3:named>Prog Model</mb3:named> <mb3:serviceAction objectType="demo.MixinMenu" id="mixins"/> <mb3:serviceAction objectType="demo.CompositeValueTypeMenu" id="compositeValueTypes"/> + <mb3:serviceAction objectType="demo.ScalarValueTypeMenu" id="scalarValueTypes"/> <mb3:serviceAction objectType="demo.EmbeddedTypeMenuJpa" id="embeddedTypes"/> <mb3:serviceAction objectType="demo.EmbeddedTypeMenuJdo" id="embeddedTypes"/> </mb3:section> diff --git a/examples/demo/domain/src/main/resources/static/css/application.css b/examples/demo/domain/src/main/resources/static/css/application.css index ba441dea35..ccc92ee0e0 100644 --- a/examples/demo/domain/src/main/resources/static/css/application.css +++ b/examples/demo/domain/src/main/resources/static/css/application.css @@ -352,7 +352,7 @@ tr.odd.custom2 > td, .navbar-nav.primary ul.dropdown-menu, .navbar-nav.secondary ul.dropdown-menu, .navbar-nav.tertiary ul.dropdown-menu { - max-height: 800px; + max-height: 850px; } div.sect1 > h2 {
