title: Customize JPA field name mapping using EclipseLink
body: <p>I need to map camel-case names to underscore-separated names in my current project, which uses EclipseLink, due to historical reasons. I know we can customize name mapping individually in JPA, but we have a long list of camel-case names to change, so we want to avoid that kind of boilerplate codes if all possible. </p>
  
  <p>What I want to achieve is as follows. Suppose we have an entity class as below:</p>
  
  <pre><code>@Entity
  public class FooBar {
      @Id @GeneratedValue
      private Long id;
  
      @Temporal( TemporalType.TIMESTAMP )
      private Date dateCreated;
  }
  </code></pre>
  
  <p>I want this class maps to a table with name "foo_bar" and columns "id" and "date_created". Note that all names in database are in lower case.</p>
  
  <p>I googled around, and found a solution for changing table names. However, I can't figure out how to change field names in an entity class. </p>
  
  <p>Below is my name-mapping customizer, where the method <code>updateFieldNameMappings()</code> is not mapping <code>fieldName</code> to <code>field_name</code>, which is what I want to achieve. The problem boils down to how to get the field name as in the class definition. So, how do I do that in EclipseLink?</p>
  
  <pre><code>public class JpaNameMappingCustomizer implements SessionCustomizer {
  
      @Override
      public void customize( Session session ) throws Exception {
          Map&lt;Class, ClassDescriptor&gt; descs = session.getDescriptors();
          Collection&lt;ClassDescriptor&gt; descriptors = descs.values();
  
          // This code assumes single table per descriptor!
          for (ClassDescriptor desc : descriptors) {
              updateTableNameMapping( desc );
              updateFieldNameMapping( desc );
          }
      }
  
      private void updateTableNameMapping ( ClassDescriptor desc ) {
          Class clazz = desc.getJavaClass();
          String tableName = camelCaseToUnderscore( clazz.getSimpleName() );
          desc.setTableName( tableName );
      }
  
      private void updateFieldNameMapping ( ClassDescriptor desc ) {
          // build name maps
          Field[] fields = desc.getJavaClass().getDeclaredFields();
          String tableName = desc.getTableName();
          Map&lt;String,String&gt; nameMap = new HashMap&lt;&gt;();
          String prefix = tableName + ".";
          for( Field field : fields ) {
              String name = field.getName();
              String key = prefix + name.toUpperCase();
              String value = prefix + camelCaseToUnderscore( name );
              nameMap.put( key, value );
          }
  
          for (DatabaseMapping mapping : desc.getMappings()) {
              if (mapping.isDirectToFieldMapping()) {
                  DirectToFieldMapping directMapping = (DirectToFieldMapping) mapping;
                  String oldFieldName = directMapping.getFieldName(); // format: table_name.FIELD
                  directMapping.setFieldName( nameMap.get( oldFieldName ) );
              }
          }
      }
  
      private String camelCaseToUnderscore( String camelCase ) {
          return camelCase.trim().replaceAll("(?&lt;!^)[A-Z](?!$)", "_$0").toLowerCase();
      }
  }
  </code></pre>
  
  <p><strong>edit 11/10/13</strong>
  I did some hacking and changed the customizer. The <code>updateFieldNameMapping()</code> still doesn't do the trick. It seems to me that this statement <code>directMapping.setFieldName( nameMap.get( oldFieldName ) )</code> inside the method doesn't actually change the field name mapping, which really confuses me.</p>
  
  <p><strong>edit 11/11/13</strong>
  I forgot to make it clear that I had the <code>eclipselink.session.customizer</code> enabled in the <code>persistence.xml</code>. Namely, I have a line like below in the <code>persistence.xml</code>: </p>
  
  <pre><code>&lt;property name="eclipselink.session.customizer" value="pkg.JpaNameMappingCustomizer"/&gt;
  </code></pre>