Podam does not work in case of pojos, created by XJC

22 views
Skip to first unread message

Matjaž Kranjc

unread,
Dec 2, 2020, 8:45:34 AM12/2/20
to PODAM

Hi,
I have a case, when classes are generated with XJC.

part of XSD:
<xs:element name="LRN" minOccurs="0" type="LRNContentType">
  <xs:annotation>
    <xs:documentation>
       <description value="LRN" />
       <format value="an..22" />
      <optionality value="D" />
     </xs:documentation>
  </xs:annotation>
</xs:element>

which turns out to java code:
@XmlElement(name = "LRN")
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
@XmlSchemaType(name = "token")
protected String lrn;

public String getLRN() {
   return lrn;
}
public void setLRN(String value) {
   this.lrn = value;
}

and then another example:
<xs:element name="TIRHolderIdentificationNumber" minOccurs="0" type="TIRHolderIdentificationNumberContentType">
  <xs:annotation>
    <xs:documentation>
      <description value="TIR holder identification number" />
      <format value="an..17" />
      <optionality value="D" />
    </xs:documentation>
   </xs:annotation>
</xs:element>

which turns out to be:
@XmlElement(name = "TIRHolderIdentificationNumber")
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
@XmlSchemaType(name = "token")
protected String tirHolderIdentificationNumber;

public String getTIRHolderIdentificationNumber() {
   return tirHolderIdentificationNumber;
}
public void setTIRHolderIdentificationNumber(String value) {
   this.tirHolderIdentificationNumber = value;
}

By the naming convention this is correct so I made a workaround like this:
public class XjcCompatibleClassInfoStrategy extends AbstractClassInfoStrategy {
    ...

  protected String extractFieldNameFromMethod(String methodName, Pattern pattern) {
    String candidateField = pattern.matcher(methodName).replaceFirst("");

     // we have all capitals like MRN or LRN, let's make them all small.
     if (candidateField.toUpperCase().equals(candidateField)) {
         return candidateField.toLowerCase();
     }

     /*
      * Default XJC respect Java Bean convention: If the first two letters of a property
      * name are uppercase, no capitalization or decapitalization is applied to the get
      * and set methods.
      *
      * Podam on the other hand do not take this into account so it does not find such
      * fields.
      */
    // method name starts with 2 or more capitals
    if (candidateField.substring(0, 2).toUpperCase().equals(candidateField.substring(0, 2))) {
       // now let's lowercase all but last in the row of upper cases
       char[] candidate = candidateField.toCharArray();
       char[] newName = new char[candidate.length];
       boolean noMoreCapitals = false;
       for (int i = 0; i < candidate.length; i++) {
         if (i >= candidate.length - 2 || noMoreCapitals) {
           // just copy last character
           newName[i] = candidate[i];
         } else if (Character.isUpperCase(candidate[i]) && Character.isUpperCase(candidate[i + 1])) {
           newName[i] = Character.toLowerCase(candidate[i]);
         } else {
           newName[i] = candidate[i];
           noMoreCapitals = true;
         }
       }
       return new String(newName);
     }
     return super.extractFieldNameFromMethod(methodName, pattern);
  }

    ...
}

I think podam should take care of this by default?

Cheers, Matjaz

Daniil Ivanov

unread,
Dec 5, 2020, 12:02:26 PM12/5/20
to PODAM
Hi,

  If you have a property

protected String tirHolderIdentificationNumber;

and a getter

public String getTIRHolderIdentificationNumber();

This really doesn't follow the naming convention.

This is what is written in the documentation JavaBeans specification:
Thus when we extract a property or event name from the middle of an existing Java name, wenormally convert the first character to lower case. However to support the occasional use of allupper-case names, we check if the first two characters of the name are both upper case and ifso leave it alone.
So for example,
“FooBah” becomes “fooBah”
“Z” becomes “z”
“URL” becomes “URL”

Following this logic LRN and TIRHolderIdentificationNumber must remain unchanged in the variable name and in the setter and getter.
However, XJC converted Acronym to lower case, but not in method names, but in variable name only.

This also creates a potential problem if you have let say LRN, Lrn and lrn variables, this will absolutely confuse not only Podam, but even human developers.

You did the right thing by creating custom ClassInfoStrategy to deal with XJC specificity.

Thanks, Daniil

Matjaž Kranjc

unread,
Dec 5, 2020, 1:33:37 PM12/5/20
to PODAM
Thank you Danilo,

you are correct, it does create unnecesarry confusion but unfortunately I cannot do anything about it since the XSDs are provided by another service and XJC binding to change default behaviour is nearly impossible to do on our project. Let me just say it creates 1600 pojos just for this service alone.

The change was just a suggestion from me, because this is default XJC behaviour and maybe you could add another implementation, that would cover this case and would be triggered by some flag.

I like podam a lot, it does it's job very well. Keep up the good work.

Cheers!

p.s.
I hope you will tackle Pattern as well in the near future (JSR303) :)

sobota, 05. december 2020 ob 18:02:26 UTC+1 je oseba daniil...@gmail.com napisala:

Daniil Ivanov

unread,
Dec 5, 2020, 4:45:06 PM12/5/20
to PODAM
However, you are right. Podam has a problem with all capitals fields.
I fixed this and will do release at some point.

Thanks, Daniil
Reply all
Reply to author
Forward
0 new messages