argoyle / tapestry-tagselect

Tapestry-tagselect is a select component for Tapestry 5 similar to the version selector in recent JIRA-versions.
Other
12 stars 2 forks source link

Could not find a coercion from type java.lang.String to type - Single #3

Closed ghost closed 13 years ago

ghost commented 13 years ago

Ajax failure: Status 500 for /eprs/purchase_request/update.purchaserequestform.pr: Failure writing parameter 'value' of component purchase_request/Update:purchaserequestform.authorizer: Could not find a coercion from type java.lang.String to type org.healthresearch.eprs.entities.ApplicationUser. Communication with the server failed: Failure writing parameter 'value' of component purchase_request/Update:purchaserequestform.authorizer: Could not find a coercion from type java.lang.String to type org.healthresearch.eprs.entities.ApplicationUser.

Should we use hidden values for each new object similar to addrow?

argoyle commented 13 years ago

Was this the problem you got when no encoder was specified? What would a good solution be? Just failing earlier and/or with a relevant error message instead of the coercion problem?

ghost commented 13 years ago

I'm using the value encoder with a single plus object and receive the error on submit.

public ValueEncoder<ApplicationUser> getApplicationUserEncoder() {
    return new ValueEncoder<ApplicationUser>() {
        public String toClient(ApplicationUser value) {
            return value.getId().toString();
        }

        public ApplicationUser toValue(String clientValue) {
            return (ApplicationUser) session.get(ApplicationUser.class, clientValue);
        }
    };
}
argoyle commented 13 years ago

Found a problem where I just set the string-value instead of using the encoder. Should be fixed by the above commit.

ghost commented 13 years ago

Failed Test

T E S T S

Running se.unbound.tapestry.tagselect.components.TagSelectTest log4j:WARN No appenders could be found for logger (org.apache.tapestry5.ioc.RegistryBuilder). log4j:WARN Please initialize the log4j system properly.

Application Exception

An unexpected application exception has occurred.

Render queue error in org.apache.tapestry5.internal.structure.RenderPhaseEventHandler$1@3212a8: Failure reading parameter 'encoder' of component PageWithEncodedTags:tags: Could not find a coercion from type se.unbound.tapestry.tagselect.helpers.TagValueEncoder to type se.unbound.tapestry.tagselect.services.LabelAwareValueEncoder.

Application Exception

An unexpected application exception has occurred.

Render queue error in org.apache.tapestry5.internal.structure.RenderPhaseEventHandler$1@26f144: Failure reading parameter 'encoder' of component PageWithEncodedTags:tags: Could not find a coercion from type se.unbound.tapestry.tagselect.helpers.TagValueEncoder to type se.unbound.tapestry.tagselect.services.LabelAwareValueEncoder.

java.lang.IllegalArgumentException: Can not set se.unbound.tapestry.tagselect.services.LabelAwareValueEncoder field se.unbound.tapestry.tagselect.components.TagSelect.encoder to se.unbound.tapestry.tagselect.components.TagSelectTest$ValueEncoderMock at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150) at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63) at java.lang.reflect.Field.set(Field.java:657) at se.unbound.tapestry.tagselect.components.TagSelectTest.assignValue(TagSelectTest.java:224) at se.unbound.tapestry.tagselect.components.TagSelectTest.setPropertyValue(TagSelectTest.java:203) at se.unbound.tapestry.tagselect.components.TagSelectTest.onAutocompleteReturnAStreamResponseWithTheGeneratedMarkup(TagSelectTest.java:157) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53) at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:119) at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:101) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103) at $Proxy0.invoke(Unknown Source) at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:150) at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:91) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69) java.lang.IllegalArgumentException: Can not set se.unbound.tapestry.tagselect.services.LabelAwareValueEncoder field se.unbound.tapestry.tagselect.components.TagSelect.encoder to se.unbound.tapestry.tagselect.components.TagSelectTest$ValueEncoderMock at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:146) at sun.reflect.UnsafeFieldAccessorImpl.throwSetIllegalArgumentException(UnsafeFieldAccessorImpl.java:150) at sun.reflect.UnsafeObjectFieldAccessorImpl.set(UnsafeObjectFieldAccessorImpl.java:63) at java.lang.reflect.Field.set(Field.java:657) at se.unbound.tapestry.tagselect.components.TagSelectTest.assignValue(TagSelectTest.java:224) at se.unbound.tapestry.tagselect.components.TagSelectTest.setPropertyValue(TagSelectTest.java:203) at se.unbound.tapestry.tagselect.components.TagSelectTest.onAutocompleteIgnoresAlreadySelectedItemsInTheGeneratedMarkup(TagSelectTest.java:177) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:76) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184) at org.junit.runners.ParentRunner.run(ParentRunner.java:236) at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53) at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:119) at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:101) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at org.apache.maven.surefire.booter.ProviderFactory$ClassLoaderProxy.invoke(ProviderFactory.java:103) at $Proxy0.invoke(Unknown Source) at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:150) at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcess(SurefireStarter.java:91) at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:69) Tests run: 12, Failures: 3, Errors: 4, Skipped: 0, Time elapsed: 8.89 sec <<< FAILURE! Running se.unbound.tapestry.tagselect.services.TagSelectModuleTest Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.003 sec

Results :

Failed tests: componentUsesEncoderDuringSubmitIfSet(se.unbound.tapestry.tagselect.components.TagSelectTest) onAutocompleteReturnAStreamResponseWithTheGeneratedMarkup(se.unbound.tapestry.tagselect.components.TagSelectTest): markup expected:<

</h...> but was:<</h...> onAutocompleteIgnoresAlreadySelectedItemsInTheGeneratedMarkup(se.unbound.tapestry.tagselect.components.TagSelectTest): markup expected:<
argoyle commented 13 years ago

My Jenkins-server told me while I had dinner. Fixed and pushed now.

ghost commented 13 years ago

lol nice! Getting closer, new bug I'm seeing with the Label encoder

Caused by: org.apache.tapestry5.ioc.internal.util.TapestryException: Failure reading parameter 'encoder' of component purchase_request/Index:purchaserequestform.authorizer: Could not find a coercion from type org.healthresearch.eprs.components.PurchaseRequestForm$4 to type org.healthresearch.eprs.services.LabelAwareValueEncoder. [at classpath:org/healthresearch/eprs/components/PurchaseRequestForm.tml, line 100]

argoyle commented 13 years ago

I think that's a change needed in your code. The get-method probably return a regular ValueEncoder which can't be coerced to my LabelAwareValueEncoder (I had one such error myself).

ghost commented 13 years ago

Ajax failure: Status 500 for /eprs/purchase_request/update.purchaserequestform.pr: Failure writing parameter 'value' of component purchase_request/Update:purchaserequestform.authorizer: Could not find a coercion from type java.lang.String to type org.healthresearch.eprs.entities.ApplicationUser. Communication with the server failed: Failure writing parameter 'value' of component purchase_request/Update:purchaserequestform.authorizer: Could not find a coercion from type java.lang.String to type org.healthresearch.eprs.entities.ApplicationUser.

This is still happening with singles, I changed the following code and it seem to resolve the issue, however it didn't commit the values to my main object

Ajax failure: Status 500 for /eprs/purchase_request/update.purchaserequestform.pr: Failure writing parameter 'value' of component purchase_request/Update:purchaserequestform.authorizer: Could not find a coercion from type java.lang.String to type org.healthresearch.eprs.entities.ApplicationUser. Communication with the server failed: Failure writing parameter 'value' of component purchase_request/Update:purchaserequestform.authorizer: Could not find a coercion from type java.lang.String to type org.healthresearch.eprs.entities.ApplicationUser.

ghost commented 13 years ago

sorry wrong code } else if (items.length > 0) { // value = items[0].toString(); this.toValue(items[0]); } else {

argoyle commented 13 years ago

Hmmm...But items[0] is already a string in that place and you really want it to use the encoder to convert it to a ApplicationUser. Can you change it back and set a breakpoint inside toValue and see if it tries to use the encoder?

ghost commented 13 years ago

I'm sorry, that was my test code before I realized it was a string. If fails at this.value = this.toValue(items[0]);

giving me this error Caused by: org.apache.tapestry5.ioc.internal.util.TapestryException: Failure writing parameter 'value' of component purchase_request/Index:purchaserequestform.authorizer: Could not find a coercion from type java.lang.String to type org.healthresearch.eprs.entities.ApplicationUser. [at classpath:org/healthresearch/eprs/components/PurchaseRequestForm.tml, line 100] at org.apache.tapestry5.internal.transform.ParameterWorker$2$1.writeToBinding(ParameterWorker.java:364) at org.apache.tapestry5.internal.transform.ParameterWorker$2$1.set(ParameterWorker.java:310) at org.apache.tapestry5.internal.transform.BridgeClassTransformation$BridgeTransformField$WrapFieldHandleForFieldValueConduitAsFieldConduit.set(BridgeClassTransformation.java:215) at org.healthresearch.eprs.components.TagSelect.set_value(TagSelect.java) at org.healthresearch.eprs.components.TagSelect.updateValue(TagSelect.java:131) at org.healthresearch.eprs.components.TagSelect.processSubmission(TagSelect.java:117) at org.apache.tapestry5.corelib.base.AbstractField.processSubmission(AbstractField.java:192) at org.apache.tapestry5.corelib.base.AbstractField.access$100(AbstractField.java:38) at org.apache.tapestry5.corelib.base.AbstractField$ProcessSubmission.execute(AbstractField.java:94) at org.apache.tapestry5.corelib.base.AbstractField$ProcessSubmission.execute(AbstractField.java:88) at org.apache.tapestry5.corelib.components.Form.executeStoredActions(Form.java:644) ... 84 more

When I change this.value = this.toValue(items[0]); to this.toValue(items[0]); it seems to work fine.

ghost commented 13 years ago

so I'm assuming not setting the value with the encoded value is the reason it's not updating my purchaserRequest object

ghost commented 13 years ago

Strange I got it working. not sure what I did differently. Now I need to figure out how to get your label encoder working. What did you say you did to your encoder to get it to work?

argoyle commented 13 years ago

And you are using an encoder I assume? Did you see if it tried to use it? It seems like it hasn't since it's still a string.

ghost commented 13 years ago

Yup that is working now, I'm not sure why it was failing there to began with. Strange!

argoyle commented 13 years ago

You have to change it from implementing the regular ValueEncoder to implementing my LabelAwareValueEncoder instead and thereby implementing the getLabel-method. You can see TagValueEncoder in src/test/java/se/unbound/tapestry/tagselect/helpers.

argoyle commented 13 years ago

Just moved LabelAwareValueEncoder to another package so you don't think it's gone if you update.

ghost commented 13 years ago

I'm getting a brain dump of tapestry, please forgive me if some of these questions seem simple.

I'm very confused with the encoders. I have one setup in my page class that looks like this.

I'm slightly confused how to use it with LabelAwareValueEncoder

@SuppressWarnings("unchecked")
public ValueEncoder getCommontatorEncoder() {
    return new ValueEncoder<ApplicationUser>() {
        public String toClient(ApplicationUser value) {
            return String.valueOf(value.getId());
        }

        public ApplicationUser toValue(String clientValue) {
            if (String.valueOf(pr.getAuthorizer().getId()).equals(clientValue)) {
                return pr.getAuthorizer();
            }                
            return null; 
        }
    };
}
argoyle commented 13 years ago

Just change it to:

 @SuppressWarnings("unchecked")
 public LabelAwareValueEncoder getCommontatorEncoder() {
     return new LabelAwareValueEncoder<ApplicationUser>() {
         public String toClient(ApplicationUser value) {
             return String.valueOf(value.getId());
         }

         public ApplicationUser toValue(String clientValue) {
             if (String.valueOf(pr.getAuthorizer().getId()).equals(clientValue)) {
                 return pr.getAuthorizer();
             }
             return null;
         }

         public String getLabel(ApplicationUser value) {
             return value.getEmail()); // TODO: Change this to the correct label-value.
         }
     };
 }
ghost commented 13 years ago

looks like I finally got the single working properly, I'm a little confused with this chunk of code

â–½

argoyle commented 13 years ago

Wow. Strange. That's the drop down arrow but I wonder where that value came from. I use a unicode-character there. Could it be an encoding-issue perhaps? I use Ubuntu Linux and it works for me. Maybe I can replace it with a HTML entity-value instead. Or maybe even an image. Might be more safe.

ghost commented 13 years ago

now that you mention it, I remember a very strange looking triangle a while ago. I never knew what it did or was. If I clicked on it, I received the following error.

authorizer is not defined onclick()

argoyle commented 13 years ago

Strange. I'll see if I can change it to an image instead (and fix the onclick-javascript if it still doesn't work as well).

ghost commented 13 years ago

I seem to be struggling a little bit with getting the collection version to work.

I have three tables purchaseRequest - main object - OneToMany / commentators commentators - purchaseRequest Users - ManyToOne purchaseRequest/applicationUser applicationUser - system users - OneToMany commentators.

following template code t:id="commentators" t:value="pr.prCommentators" t:encoder="applicationUserEncoder"

onProvide SelectModel onProvideCompletionsFromCommentators(String partial) { HashSet hashset = new HashSet(); partial = partial.toUpperCase();

    List<ApplicationUser> applicationUsers = session.createCriteria(ApplicationUser.class).list(); 

    for (ApplicationUser applicationUser : applicationUsers) {            

        if (applicationUser.getName().toUpperCase().startsWith(partial)) {
                hashset.add(applicationUser);
        }

        if (applicationUser.getEmail().toUpperCase().startsWith(partial)) {
                hashset.add(applicationUser);
        }
    }

    return selectModelFactory.create(new ArrayList<ApplicationUser>(hashset), "Label");
}

and finally my encoder

@SuppressWarnings("unchecked")
 public LabelAwareValueEncoder getCommontatorEncoder() {
     return new LabelAwareValueEncoder<PrCommentator>() {
         public String toClient(PrCommentator value) {
             return String.valueOf(value.getTempId());
         }

         public PrCommentator toValue(String clientValue) {
            Long key = new Long(clientValue);

            for(PrCommentator _commentator : pr.getPrCommentators()) {
                if (_commentator.getTempId() == key) {
                    return _commentator;
                }
            }
            return null;
         }

         public String getLabel(PrCommentator value) {
             return value.getCommentator().getLabel();
         }
     };
 }

I'm getting the following error Caused by: java.lang.ClassCastException: org.healthresearch.eprs.entities.ApplicationUser cannot be cast to org.healthresearch.eprs.entities.PrCommentator at org.healthresearch.eprs.components.PurchaseRequestForm$5.toClient(PurchaseRequestForm.java:527) at org.healthresearch.eprs.components.TagSelect.toClient(TagSelect.java:165)

I'm assuming it's because I'm not creating a new instance of PrCommentator. Any suggestions?

argoyle commented 13 years ago

The select model returned from onProvideCompletionsFromCommentators must contain PrCommentator and not ApplicationUser. You could create "fake" PrCommentator-instances since you know the ApplicationUser and I guess you know the PurchaseRequest as well? That's how I do it with my AccountTag handling where I can tag an account with multiple tags.

argoyle commented 13 years ago

I just pushed a new version which uses an image instead of the unicode-character.

argoyle commented 13 years ago

By the way, can you close the issues when you have verified that the problem is solved?

ghost commented 13 years ago

How do you "fake" the PrCommentator-instance? By the way, the drop down arrow displays poorly, feel free to let it go and I'll repair it later today.

argoyle commented 13 years ago

In my case with my AccountTag I create a new instance of AccountTag for each of the possible tags in the database and for each AccountTag I set the Account to the one I'm editing. The AccountTag is a regular JPA entity but the fake ones are not persisted yet. I do take care to use any already persisted AccountTags so I don't end up with unique key constraint violations.

argoyle commented 13 years ago

The drop down arrow displays fine at my end in Chromium but please fix it at your end and send a pull request. :-)

argoyle commented 13 years ago

George, did you get anywhere on the drop down arrow display? I was thinking about releasing version 1.3 since it feels like the component works as it should as far as I see. Do you agree?

ghost commented 13 years ago

Hi Argoyle, I started working on the interface piece of it and somehow that led to me developing an entirely new interface on top of your backend piece. So in short yes, but no. I was hoping to upload my work when I got a bit further for you to cleanup. For now I would say you could release version three if you were able to resolve the the drop down js error.

While working with this, I noticed you weren't excepting any of the default autocomplete parameters, ie frequency, etc. That might be handy to add in.

I'll keep you posted on my progress, I think it's going to add a tremendous amount or value to the component.

argoyle commented 13 years ago

That sounds great. I'm no UI-guy so if you can create a better looking component I'm all for it.

I think the javascript error has been taken care of but I'll run through it all once again just to be sure and then I'll release it.

I'm closing this issue as well then.

ghost commented 13 years ago

lol, no prob, I'm a much better UI guy than a backend guy. Hopefully it works out.