001package com.avaje.ebean.config; 002 003/** 004 * Converts between Camel Case and Underscore based names for both table and 005 * column names (and is the default naming convention in Ebean). 006 * 007 * @author emcgreal 008 * @author rbygrave 009 */ 010public class UnderscoreNamingConvention extends AbstractNamingConvention { 011 012 /** 013 * Force toUnderscore to return in upper case. 014 */ 015 private boolean forceUpperCase = false; 016 017 /** 018 * The digits compressed. 019 */ 020 private boolean digitsCompressed = true; 021 022 /** 023 * Create with a given sequence format. 024 * 025 * @param sequenceFormat the sequence format 026 */ 027 public UnderscoreNamingConvention(String sequenceFormat) { 028 super(sequenceFormat); 029 } 030 031 /** 032 * Create with a sequence format of "{table}_seq". 033 */ 034 public UnderscoreNamingConvention() { 035 super(); 036 } 037 038 /** 039 * Returns the last part of the class name. 040 * 041 * @param beanClass the bean class 042 * @return the table name from class 043 */ 044 public TableName getTableNameByConvention(Class<?> beanClass) { 045 046 return new TableName(getCatalog(), getSchema(), toUnderscoreFromCamel(beanClass.getSimpleName())); 047 } 048 049 /** 050 * Converts Camel case property name to underscore based column name. 051 * 052 * @return the column from property 053 */ 054 public String getColumnFromProperty(Class<?> beanClass, String propertyName) { 055 056 return toUnderscoreFromCamel(propertyName); 057 } 058 059 /** 060 * Converts underscore based column name to Camel case property name. 061 * 062 * @param beanClass the bean class 063 * @param dbColumnName the db column name 064 * @return the property from column 065 */ 066 public String getPropertyFromColumn(Class<?> beanClass, String dbColumnName) { 067 return toCamelFromUnderscore(dbColumnName); 068 } 069 070 /** 071 * Return true if the result will be upper case. 072 * <p> 073 * False if it will be lower case. 074 * </p> 075 */ 076 public boolean isForceUpperCase() { 077 return forceUpperCase; 078 } 079 080 /** 081 * Set to true to make the result upper case. 082 */ 083 public void setForceUpperCase(boolean forceUpperCase) { 084 this.forceUpperCase = forceUpperCase; 085 } 086 087 /** 088 * Returns true if digits are compressed. 089 */ 090 public boolean isDigitsCompressed() { 091 return digitsCompressed; 092 } 093 094 /** 095 * Sets to true for digits to be compressed (without a leading underscore). 096 */ 097 public void setDigitsCompressed(boolean digitsCompressed) { 098 this.digitsCompressed = digitsCompressed; 099 } 100 101 /** 102 * Convert and return the string to underscore from camel case. 103 */ 104 protected String toUnderscoreFromCamel(String camelCase) { 105 106 int lastUpper = -1; 107 StringBuilder sb = new StringBuilder(camelCase.length()+4); 108 for (int i = 0; i < camelCase.length(); i++) { 109 char c = camelCase.charAt(i); 110 111 if ('_' == c) { 112 // Underscores should just be passed through 113 sb.append(c); 114 lastUpper = i; 115 } else if (Character.isDigit(c)) { 116 if (i > lastUpper + 1 && !digitsCompressed) { 117 sb.append("_"); 118 } 119 sb.append(c); 120 lastUpper = i; 121 122 } else if (Character.isUpperCase(c)) { 123 if (i > lastUpper + 1) { 124 sb.append("_"); 125 } 126 sb.append(Character.toLowerCase(c)); 127 lastUpper = i; 128 129 } else { 130 sb.append(c); 131 } 132 } 133 String ret = sb.toString(); 134 if (forceUpperCase) { 135 ret = ret.toUpperCase(); 136 } 137 return ret; 138 } 139 140 /** 141 * Convert and return the from string from underscore to camel case. 142 */ 143 protected String toCamelFromUnderscore(String underscore) { 144 145 StringBuilder result = new StringBuilder(underscore.length()); 146 String[] vals = underscore.split("_"); 147 148 for (int i = 0; i < vals.length; i++) { 149 String lower = vals[i].toLowerCase(); 150 if (i > 0) { 151 char c = Character.toUpperCase(lower.charAt(0)); 152 result.append(c); 153 result.append(lower.substring(1)); 154 } else { 155 result.append(lower); 156 } 157 } 158 159 return result.toString(); 160 } 161}