[MGNLUI-6485] Link field validation is not possible Created: 23/Dec/20  Updated: 06/Apr/22

Status: Accepted
Project: Magnolia UI
Component/s: None
Affects Version/s: 6.2.5
Fix Version/s: None

Type: Bug Priority: Low
Reporter: Richard Gange Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: 22m
Original Estimate: Not Specified

Attachments: PNG File area-nodes.png     PNG File error.png    
Issue Links:
Relates
relates to MGNLUI-6406 Complex fields doesn't allow validato... Closed
relation
is related to CONTEDIT-297 Browse for asset: Exception on click ... Closed
Template:
Acceptance criteria:
Empty
Task DoD:
[ ]* Doc/release notes changes? Comment present?
[ ]* Downstream builds green?
[ ]* Solution information and context easily available?
[ ]* Tests
[ ]* FixVersion filled and not yet released
[ ]  Architecture Decision Record (ADR)
Bug DoR:
[ ]* Steps to reproduce, expected, and actual results filled
[ ]* Affected version filled
Date of First Response:

 Description   

Validation on link fields is no longer possible (since 6.2.5)

Reproduce
Create a dialog with the following configuration:

form:
  properties:
    link:
      $type: linkField
      chooser:
        workbenchChooser:
          appName: pages-app
      label: Main Page Path
      validators:
        ukSiteOnly:
          class: info.magnolia.ui.field.RegexpValidatorDefinition
          pattern: (^\/uk\/.*)|(^$)
          errorMessage: Page must be under /uk.

Using the dialog, select a page and try to save the dialog.

Observe the error:

Caused by:

Caused by: java.lang.ClassCastException: info.magnolia.ui.datasource.jcr.JcrNodeWrapper cannot be cast to java.lang.String
	at com.vaadin.data.validator.RegexpValidator.apply(RegexpValidator.java:33) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.Binder$ValidatorAsConverter.convertToModel(Binder.java:1275) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.Converter$2.lambda$convertToModel$5daf174e$1(Converter.java:167) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.SimpleResult.flatMap(SimpleResult.java:66) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.ValidationResultWrap.flatMap(ValidationResultWrap.java:66) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.Converter$2.convertToModel(Converter.java:167) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.Converter$2.convertToModel(Converter.java:165) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.Converter$2.convertToModel(Converter.java:165) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.Binder$BindingImpl.doConversion(Binder.java:1109) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.Binder$BindingImpl.doValidation(Binder.java:1126) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.Binder$BindingImpl.access$1400(Binder.java:1001) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.Binder.lambda$validateBindings$11(Binder.java:2066) ~[vaadin-server-8.9.4.jar:8.9.4]
	at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:193) ~[?:1.8.0_261]
	at java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1384) ~[?:1.8.0_261]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:482) ~[?:1.8.0_261]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) ~[?:1.8.0_261]
	at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708) ~[?:1.8.0_261]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_261]
	at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499) ~[?:1.8.0_261]
	at com.vaadin.data.Binder.validateBindings(Binder.java:2067) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.Binder.validate(Binder.java:2006) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.data.Binder.validate(Binder.java:1985) ~[vaadin-server-8.9.4.jar:8.9.4]
	at info.magnolia.ui.editor.FormPresenter.lambda$validateBoundProperties$6(FormPresenter.java:133) ~[magnolia-ui-framework-6.2.5.jar:?]
	at java.util.HashMap.forEach(HashMap.java:1289) ~[?:1.8.0_261]
	at info.magnolia.ui.editor.FormPresenter.validateBoundProperties(FormPresenter.java:131) ~[magnolia-ui-framework-6.2.5.jar:?]
	at info.magnolia.ui.editor.FormView.validate(FormView.java:182) ~[magnolia-ui-framework-6.2.5.jar:?]
	at info.magnolia.ui.contentapp.action.CommitAction.execute(CommitAction.java:78) ~[magnolia-ui-framework-6.2.5.jar:?]
	at info.magnolia.ui.api.action.AbstractActionExecutor.execute(AbstractActionExecutor.java:62) ~[magnolia-ui-api-6.2.5.jar:?]
	at info.magnolia.ui.dialog.ActionExecution.execute(ActionExecution.java:73) ~[magnolia-ui-framework-6.2.5.jar:?]
	at info.magnolia.ui.dialog.ActionButton.lambda$new$d31ec881$1(ActionButton.java:63) ~[magnolia-ui-framework-6.2.5.jar:?]
	at sun.reflect.GeneratedMethodAccessor900.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_261]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_261]
	at com.vaadin.event.ListenerMethod.receiveEvent(ListenerMethod.java:499) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:273) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.event.EventRouter.fireEvent(EventRouter.java:237) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.server.AbstractClientConnector.fireEvent(AbstractClientConnector.java:1014) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.ui.Button.fireClick(Button.java:384) ~[vaadin-server-8.9.4.jar:8.9.4]
	at com.vaadin.ui.Button$1.click(Button.java:57) ~[vaadin-server-8.9.4.jar:8.9.4]
	at sun.reflect.GeneratedMethodAccessor899.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_261]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_261]
	at com.vaadin.server.ServerRpcManager.applyInvocation(ServerRpcManager.java:155) ~[vaadin-server-8.9.4.jar:8.9.4]
	... 109 more

Workaround:
If you are validating a specific root path then use a datasource with a rootPath configuration.

form:
  properties:
    link:
      $type: linkField
      datasource:
        $type: jcrDatasource
        workspace: website
        rootPath: /uk
        allowedNodeTypes:
          pages: mgnl:page
      label: Main Page Path


 Comments   
Comment by Roman Kovařík [ 23/Dec/20 ]

What about

form:
 properties:
   link:
     $type: linkField
     # chooser: #this configuration is deprecated
     #   workbenchChooser:
     #     appName: pages-app
     datasource:
       $type: jcrDatasource
       workspace: website
       rootPath: /uk
Comment by Richard Gange [ 23/Dec/20 ]

Tried also:

form:
  properties:
    link:
      $type: linkField
      datasource:
        $type: jcrDatasource
        workspace: website
        allowedNodeTypes:
          pages: mgnl:page
      label: Main Page Path
      validators:
        ukSiteOnly:
          class: info.magnolia.ui.field.RegexpValidatorDefinition
          pattern: (^\/uk\/.*)|(^$)
          errorMessage: Page must be under /uk.

Same error.

Comment by Roman Kovařík [ 23/Dec/20 ]

No wonder, the validator is still there .

Comment by Richard Gange [ 23/Dec/20 ]

Yeah, the ticket is you cannot validate a link field.

Comment by Roman Kovařík [ 23/Mar/21 ]

With 6.2.7 possible with this configuration:

linkField:
 $type: linkField
 textInputAllowed: true
 validators:
 - $type: regexpValidator
 pattern: test

There is still a minor issue: the field is marked as invalid only after clicking to commit.
To fix this (get the validation when typing already):

diff --git a/magnolia-ui-framework/src/main/java/info/magnolia/ui/field/AbstractLinkField.java b/magnolia-ui-framework/src/main/java/info/magnolia/ui/field/AbstractLinkField.java
index 28e0a30bec..e1acbf6b37 100644
--- a/magnolia-ui-framework/src/main/java/info/magnolia/ui/field/AbstractLinkField.java
+++ b/magnolia-ui-framework/src/main/java/info/magnolia/ui/field/AbstractLinkField.java
@@ -40,6 +40,7 @@ import java.util.Objects;
 import java.util.Optional;
 
 import com.vaadin.data.HasValue;
+import com.vaadin.shared.Registration;
 import com.vaadin.ui.Button;
 import com.vaadin.ui.Component;
 import com.vaadin.ui.CustomField;
@@ -116,6 +117,12 @@ public abstract class AbstractLinkField<T, P> extends CustomField<T> {
     }
 
     @Override
+    public Registration addValueChangeListener(ValueChangeListener<T> listener) {
+        hasValue.addValueChangeListener(listener);
+        return super.addValueChangeListener(listener);
+    }
+
+    @Override
Comment by Martin Haderka [ 23/Mar/21 ]

The proposed ^ configuration is working since the Link Field is represented by textLinkField.

But modification to:

linkField: 
 $type: linkField
 textInputAllowed: true
 showOptions: true
 validators: 
  $type: regexpValidator
  pattern: test

will again trigger "class info.magnolia.ui.datasource.jcr.JcrNodeWrapper cannot be cast to class java.lang.String" error.
In this case, the Link Field is represented by ComboBox.

Comment by Roman Kovařík [ 24/Mar/21 ]

 will again trigger "class info.magnolia.ui.datasource.jcr.JcrNodeWrapper cannot be cast to class java.lang.String" error. 

Similarly as adding regexp validator to any other field with non string type.

In this case, the Link Field is represented by ComboBox.

Since we can't choose value outside of the datasource, not sure what would be the validator usecase, ideally we would be able to configure the datasource to not provide invalid values (e.g. mgnl:folder nodetypes).

Comment by Martin Haderka [ 26/Mar/21 ]

 Similarly as adding regexp validator to any other field with non-string type.

Would a possible solution be to create a converter that would typecast nodes from datasource to string representation just for the regex validator?

 ...ideally we would be able to configure the datasource to not provide invalid values

Agree

Generated at Mon Feb 12 09:36:57 CET 2024 using Jira 9.4.2#940002-sha1:46d1a51de284217efdcb32434eab47a99af2938b.