1 2 Previous Next 25 Replies Latest reply on Aug 6, 2012 6:05 AM by luca.masini

    Scaffolding broken for aB123 field names

    anthonyhib

      Hi guys,

      I'm working on a project using normalized filed names like

      @Id

      private Long iD123

       

      private String aB123;

      public String getaB123();

      public void setaB123(){...}

       

      this is correct naming, however this pattern is not caught by forge scaffolding.

      Moreover the few generated is incorrect, the XXXBean generated will rely on getID123 instead of getiD123 for interacting with the Id.

       

       

      This is quite an urgent issue for us, maybe you could just point me where to look at and I can update the code myself.

       

      Thanks a bunch

      Anthony

        • 1. Re: Scaffolding broken for aB123 field names
          luca.masini

          I think that forge is correct, property getters capitalize the first letter as in JavaBean specs.

          Ciao

          • 2. Re: Scaffolding broken for aB123 field names
            koen.aers

            Hey Anthony,

             

            Like Luca, I also think that the Forge behaviour is the correct one. What exactly is the problem you see in the scaffolding when using thise names?

             

            Cheers,

            Koen

            • 3. Re: Scaffolding broken for aB123 field names
              anthonyhib

              Hi Koen and Lucas,

              first, thanks for your answer.

              I think the main point in the interpretation of the java bean naming convention.

              Everybody is ok with the URL (3 upper case letters) pattern, however as soon as there are only 2 letters with one in upper case, problems appear.

               

              We trusted eclipse getter/setter generation, and maybe that's our mistake but I guess many people are relying on it.

              I created a new class

               

              @Entity

              public class AB123_MYCLASS

              {

                 private Long iD123;

                 private Long ID456;

                 @Id

                 private Long id789;

                 private String aB123;

                 private String CD456;

                 private String ef789;

              ...

              }

               

              then generate getter and setter with eclipse, then run scaffolding.

              Results: only ef789 cd456 are visibles.

              1st issue, should forge also take care of get+ lowercase +something else pattern when scaffolding?

               

              Generating the getter and setter with forge makes everything work (of course).

               

              for eclipse, aB123 -> getaB123 setaB123

              for forge, aB123 -> getAB123 setAB123

              2nd issue, that could lead to a id interaction problem in the classes located inside the view package.

               

              Basically how should one handle a field named aFIELD ? I really think it should be getaFIELD setaFIELD.

               

              Cheers,

              Anthony

              • 4. Re: Scaffolding broken for aB123 field names
                luca.masini

                Anthony I should never answer from my iPhone

                 

                To infer the correct getter name I runned this simple snippet of code that tries to infer the variable name from the getter:

                 

                        System.out.println("variable name for getiD123() is " + Introspector.decapitalize("iD123"));

                        System.out.println("variable name for getID456() is " + Introspector.decapitalize("ID456"));

                        System.out.println("variable name for getId789() is " + Introspector.decapitalize("Id789"));

                        System.out.println("variable name for getaB123() is " + Introspector.decapitalize("aB123"));

                        System.out.println("variable name for getCD456() is " + Introspector.decapitalize("CD456"));

                        System.out.println("variable name for getEf789() is " + Introspector.decapitalize("ef789"));

                 

                and this is the output:

                 

                     variable name for getiD123() is iD123

                     variable name for getID456() is ID456

                     variable name for getId789() is id789

                     variable name for getaB123() is aB123

                     variable name for getCD456() is CD456

                     variable name for getEf789() is ef789

                 

                So I think that you're right and that forge is missing the point.

                 

                Infact the static method that tries to do the inverse work seems to be broken:

                 

                public static String capitalize( String in ) {

                          return Character.toUpperCase( in.charAt( 0 ) ) + in.substring( 1 );

                }

                 

                As you can see it doesn't take in account the JavaBean naming design pattern.

                 

                I think that this issue can be easily solved, to answer you question (if you want to fix it by yourself) the class is org.metawidget.util.simple.StringUtils, so I think you should add a private forge method that implements the inverse of Introspector.decapitalize.

                Hope this answer your question.

                 

                Ciao.

                L.

                1 of 1 people found this helpful
                • 5. Re: Scaffolding broken for aB123 field names
                  anthonyhib

                  Thanks Lucas,

                  it's weird that this issue is happening so often, I've seen it in various well known frameworks.

                  Thanks to you, I've located the places where I can **hack** my particular naming things.

                   

                  However, I'm 99% my hack is not covering all the use cases described by the spec and I won't be stupid to propose this as a patch, that would waste your time.

                   

                  In parallel, I've pinged Richard to warn him about the issue.

                   

                  Thanks a lot to you and Koen, you saved me hours.

                  Anthony

                  • 6. Re: Scaffolding broken for aB123 field names
                    kennardconsulting

                    Hi Anthony,

                     

                    Thanks for reaching out to me. I'd question whether 'getaFIELD' is actually correct JavaBean convention (see message to Luca below). However if you must support it I have good news and bad news.

                     

                    The good news is Metawidget is pluggable in many different dimensions, and has quite extensive support for plugging in different 'property styles' (as we call them) to suit JavaBeans, GroovyBeans, Scala or your own property notation. Please see http://metawidget.org/doc/reference/en/html/ch04.html#section-inspectors-base-object-propertystyle-implementing-your-own

                     

                    The bad news is the Metawidget/Forge integration is not mature with respect to letting you change Metawidget's configuration (https://issues.jboss.org/browse/FORGE-425). So you'll need to find a way to a) put your own PropertyStyle-implementation on the Forge classpath; b) update forge-scaffold-plugins/resources/.../metawidget.xml to use your new PropertyStyle. Possibly the easiest way to do this (for now) is simply unzip the forge-scaffold-faces module JAR and update the XML file.

                     

                    You may also want to ping Ryan Bradley, who has been working on Forge/Spring/Metawidget integration, to see if he has any ideas.

                     

                    Regards,

                     

                    Richard.

                    1 of 1 people found this helpful
                    • 7. Re: Scaffolding broken for aB123 field names
                      kennardconsulting

                      Hi Luca,

                       

                      I don't think you can assume that 'capitalize' needs to be the inverse of 'decapitalize'. If you look at the JavaBean spec it says...

                       

                           PropertyDescriptor: "Note that the property name should start with a lower case character, which will be capitalized in the method names"

                       

                      ...and in the java.beans.PropertyDescriptor code it does...

                       

                           public PropertyDescriptor(String propertyName, Class<?> beanClass)

                              throws IntrospectionException {

                               this(propertyName, beanClass, "is" + capitalize(propertyName), "set" + capitalize(propertyName));

                          }

                           ...

                           readMethodName = "get" + getBaseName();

                           ...

                           String getBaseName() { return capitalize(getName()); }

                           ...

                           public static String capitalize(String name) {

                                return name.substring(0, 1).toUpperCase(ENGLISH) + name.substring(1);

                           }

                       

                      ...there is no discussion about 'if the second letter is capitalized then...' (like there is for decapitalize). The only algorithm/implementation I can find is simply 'uppercase the first letter'. Is there some other algorithm for 'capitalize' that I should be using?

                       

                      Your proposed convention ('getiD123') would seem to have undesirable consequences. For example...

                       

                           public class CourtCase {

                                public String getName() {...}

                                public void settle( BigDecimal settlementAmount ) {...}

                                public boolean isolate() {...}

                           }

                       

                      ...would find 'action' methods (settle, isolate) to be JavaBean properties 'tle' and 'olate'?

                       

                      Regards,

                       

                      Richard.

                      • 8. Re: Scaffolding broken for aB123 field names
                        anthonyhib

                        Thanks Richard,

                        I mainly hacked (not only) isGetter/Setter of ForgePropertyStyle

                         

                              /*if (!StringUtils.isCapitalized(propertyName))
                              {
                                 return null;
                              }*/
                        
                        
                              return ForgeStringUtils.decapitalize(propertyName);
                           }
                        

                         

                        public class ForgeStringUtils {
                                  public static String decapitalize(String name) {
                                            if (name == null || name.length() == 0) {
                                                  return name;
                                              }
                                              if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
                                                                  Character.isUpperCase(name.charAt(0))){
                                                  return name;
                                              }
                                              char chars[] = name.toCharArray();
                                              chars[0] = Character.toLowerCase(chars[0]);
                                              return new String(chars);
                                    }
                          
                                  public static String capitalize( String in ) {
                                              if (in.length() > 1 && Character.isUpperCase(in.charAt(1)) &&
                                                                Character.isLowerCase(in.charAt(0)))
                                                      return in;
                                              return Character.toUpperCase( in.charAt( 0 ) ) + in.substring( 1 );
                                  }
                          }
                        

                         

                        Since I'm in  a hurry I did it to handle our naming convention, it is certainly not robust enough.

                        • 9. Re: Scaffolding broken for aB123 field names
                          kennardconsulting

                          Luca,

                           

                          Though I think it may be a bug, it appears Introspector.getBeanInfo really does return 'tle' and 'solate' as I describe above. Conversely, if you do new PropertyStyle( "aFIELD" ) it goes looking for a method called "setAFIELD". So I'm not sure what to think. It appears to disagree with itself!

                           

                          Probably the safest thing to do (given this is a fringe case) is to behave the same as Introspector. So I've now updated Metawidget.

                           

                          Anthony,

                           

                          Could you please try Forge using Metawidget 2.4-SNAPSHOT (https://repository.jboss.org/nexus/content/repositories/snapshots/org/metawidget/modules/metawidget-all/2.4-SNAPSHOT/), and confirm it works without needing your custom ForgePropertyStyle?

                           

                          Thanks everybody for bringing this to my attention.

                          • 10. Re: Scaffolding broken for aB123 field names
                            luca.masini

                            I think that JavaBeans specs about naming convention are an abstract concept, like love or philosophy.

                             

                            I looked up the method decapitalize that is into the Introspector and the algorithm is different and goes in the way I read in "Design Pattern" about naming convention in that old spec (I think 8.3 is the one we are interested in):

                             

                              public static String decapitalize(String name) {

                                      if (name == null || name.length() == 0) {

                                           return name;

                                      }

                                     

                                      if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) && Character.isUpperCase(name.charAt(0))){

                                           return name;

                                      }

                             

                                      char chars[] = name.toCharArray();

                                      chars[0] = Character.toLowerCase(chars[0]);

                             

                                      return new String(chars);

                            }

                             

                            As you pointed, this is different from what we can read into the PropertyDescriptor class and is similar to what I see IDE do (Eclipse and Idea).

                             

                            The fact is that I think capitalize(decapitalize(name)) should be equals to name and capitalizing the first letter this is not always true.

                             

                            I think you final solution should do the work.

                             

                            Thank you.

                             

                            L.

                            • 11. Re: Scaffolding broken for aB123 field names
                              anthonyhib

                              Hi Richard,

                              I

                              1- extracted the forge sources

                              2- modified scaffold pom to use the latest metawidget snapshot

                               

                              However I'm not sure how I need to update the 4 metawidget xml config files located in the scaffold-faces modules in order to totally ignore the custom forgePropertyStyle. I've tried the following

                               

                               

                              <?xml version="1.0"?>
                              <metawidget xmlns="http://metawidget.org"
                                          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                                          xmlns:processor="java:org.metawidget.statically.faces.component.widgetprocessor"
                                          xsi:schemaLocation="http://metawidget.org http://metawidget.org/xsd/metawidget-1.0.xsd
                                                                                          java:org.metawidget.statically.faces.component.html http://metawidget.org/xsd/org.metawidget.statically.faces.component.html-1.0.xsd
                                                                                          java:org.metawidget.inspector.composite http://metawidget.org/xsd/org.metawidget.inspector.composite-1.0.xsd"
                                          version="1.0">
                              
                              
                                        <!-- metawidget-search.xml is used to generate the search fields -->
                                
                                      <staticHtmlMetawidget xmlns="java:org.metawidget.statically.faces.component.html">
                                
                                              <inspector>
                                                      <compositeInspector xmlns="java:org.metawidget.inspector.composite" config="CompositeInspectorConfig">
                                                              <inspectors>
                                                                      <array>
                                                                              <propertyTypeInspector xmlns="java:org.metawidget.inspector.propertytype" config="org.metawidget.inspector.impl.BaseObjectInspectorConfig">
                                                                                      <propertyStyle>
                                                                                              <forgePropertyStyle id="forgePropertyStyle" xmlns="java:org.jboss.forge.scaffold.faces.metawidget.inspector.propertystyle" config="ForgePropertyStyleConfig">
                                                                                                      <project>
                                                                                                              <forgeProject/>
                                                                                                      </project>
                                                                                              </forgePropertyStyle>
                                                                                      </propertyStyle>
                                                                              </propertyTypeInspector>
                                                                              <forgeInspector xmlns="java:org.jboss.forge.scaffold.faces.metawidget.inspector" config="org.metawidget.inspector.impl.BaseObjectInspectorConfig">
                                                                                      <!--propertyStyle>
                                                                                              <forgePropertyStyle refId="forgePropertyStyle"/>
                                                                                      </propertyStyle-->
                                                                              </forgeInspector>
                                                                              <jpaInspector xmlns="java:org.metawidget.inspector.jpa" config="JpaInspectorConfig">
                                                                                      <!--propertyStyle>
                                                                                              <forgePropertyStyle refId="forgePropertyStyle"/>
                                                                                      </propertyStyle-->
                                                                              </jpaInspector>
                                                                              <beanValidationInspector xmlns="java:org.metawidget.inspector.beanvalidation" config="org.metawidget.inspector.impl.BaseObjectInspectorConfig">
                                                                                      <!--propertyStyle>
                                                                                              <forgePropertyStyle refId="forgePropertyStyle"/>
                                                                                      </propertyStyle-->
                                                                              </beanValidationInspector>
                                                                      </array>
                                                              </inspectors>
                                                      </compositeInspector>
                                              </inspector>
                                
                                                                      <inspectionResultProcessors>
                                                                                <array>
                                                                                          <notRequiredInspectionResultProcessor xmlns="java:org.jboss.forge.scaffold.faces.metawidget.inspectionresultprocessor"/>
                                                                                </array>
                                                                      </inspectionResultProcessors>
                                
                                              <widgetBuilder>
                                                      <compositeWidgetBuilder xmlns="java:org.metawidget.widgetbuilder.composite" config="CompositeWidgetBuilderConfig">
                                                              <widgetBuilders>
                                                                      <array>
                                                                              <entityWidgetBuilder xmlns="java:org.jboss.forge.scaffold.faces.metawidget.widgetbuilder" config="EntityWidgetBuilderConfig">
                                                                                      <config>
                                                                                              <forgeConfig/>
                                                                                      </config>
                                                                              </entityWidgetBuilder>
                                                                              <htmlWidgetBuilder xmlns="java:org.metawidget.statically.faces.component.html.widgetbuilder"/>
                                                                      </array>
                                                              </widgetBuilders>
                                                      </compositeWidgetBuilder>
                                              </widgetBuilder>
                              
                              
                                              <widgetProcessors>
                                                      <array>
                                                              <standardBindingProcessor xmlns="java:org.metawidget.statically.faces.component.widgetprocessor"/>
                                                              <readableIdProcessor xmlns="java:org.metawidget.statically.faces.component.widgetprocessor"/>
                                                              <standardConverterProcessor xmlns="java:org.metawidget.statically.faces.component.widgetprocessor"/>
                                                              <cssStyleProcessor xmlns="java:org.metawidget.statically.faces.component.html.widgetprocessor"/> 
                                                              <unsearchableWidgetProcessor xmlns="java:org.jboss.forge.scaffold.faces.metawidget.widgetprocessor"/>
                                                      </array>
                                              </widgetProcessors>
                              
                              
                                              <layout>
                                                      <htmlPanelGridLayout xmlns="java:org.metawidget.statically.faces.component.html.layout" config="HtmlPanelGridLayoutConfig">
                                                              <columnStyleClasses>
                                                                      <array>
                                                                              <string>label</string>
                                                                              <string>component</string>
                                                                              <string>required</string>
                                                                      </array>
                                                              </columnStyleClasses>
                                                              <messageStyleClass>
                                                                      <string>error</string>
                                                              </messageStyleClass>
                                                      </htmlPanelGridLayout>
                                              </layout>
                                
                                      </staticHtmlMetawidget> 
                              
                              
                              </metawidget>
                              

                               

                              without success, forge is still generating wrong getter/setter.

                              Second test by leaving the getter/setter generation to eclipse, then scaffolding -> the aFIELD named field isn't caught.

                               

                              Let me know if my metawidget config is silly.

                               

                              Thanks

                              Anthony

                              • 12. Re: Scaffolding broken for aB123 field names
                                kennardconsulting

                                You shouldn't need to touch the 4 metawidget.xml config files at all. Just updating the Metawidget JARs to 2.4-SNAPSHOT should be sufficient?

                                 

                                Please try reverting everything back to the original Forge distribution and try again?

                                • 13. Re: Scaffolding broken for aB123 field names
                                  anthonyhib

                                  Hi Richard,

                                  First there is still a bug in ForgePropertyStyle which excludes any accessor not having an upper case character after get/set -> so I left my fix there.

                                  Next, I removed my custom ForgeStringUtils to go back to metawidget.

                                   

                                  With your update:

                                  - Use case 1: getter/setter generated with eclipse -> scaffold is now generated however the view bean is still point to wrong field naming.

                                        String bSTRING = this.search.getBSTRING();
                                        if (bSTRING != null && !"".equals(bSTRING))
                                        {
                                           predicatesList.add(builder.like(root.<String> get("bSTRING"), '%' + bSTRING + '%'));
                                        }
                                  

                                  should be

                                   

                                        String bSTRING = this.search.getbSTRING();
                                        if (bSTRING != null && !"".equals(bSTRING))
                                        {
                                           predicatesList.add(builder.like(root.<String> get("bSTRING"), '%' + bSTRING + '%'));
                                        }
                                  

                                   

                                  this is certainly a pure forge issue.

                                   

                                  - Use case 2: getter/setter generated with forge -> works but naming used by forget is not correct

                                   

                                  Thanks a lot Richard.

                                   

                                  Message was edited by: Anthony Patricio

                                  • 14. Re: Scaffolding broken for aB123 field names
                                    anthonyhib

                                    same for the ID binding

                                    still in the view bean, the update method is wrong

                                             else

                                             {

                                                this.entityManager.merge(this.aENTITY);

                                                return "view?faces-redirect=true&id=" + this.aENTITY.getAID();

                                             }

                                     

                                    should be

                                     

                                             else

                                             {

                                                this.entityManager.merge(this.aENTITY);

                                                return "view?faces-redirect=true&id=" + this.aENTITY.getaID();

                                             }

                                    1 2 Previous Next