/* * JEF - Copyright 2009-2010 Jiyi (mr.jiyi@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.github.geequery.codegen; import java.io.File; import java.io.IOException; import java.lang.reflect.Modifier; import java.sql.SQLException; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.persistence.Table; import jef.codegen.support.OverWrittenMode; import jef.codegen.support.RegexpNameFilter; import jef.common.log.LogUtil; import jef.database.DataObject; import jef.database.DbUtils; import jef.database.annotation.PartitionKey; import jef.database.annotation.PartitionTable; import jef.database.dialect.AbstractDialect; import jef.database.dialect.ColumnType; import jef.database.dialect.ColumnType.AutoIncrement; import jef.database.dialect.ColumnType.GUID; import jef.database.dialect.ColumnType.Varchar; import jef.database.dialect.DatabaseDialect; import jef.database.meta.Column; import jef.database.meta.TableInfo; import jef.database.routing.function.KeyFunction; import jef.http.client.support.CommentEntry; import jef.tools.ArrayUtils; import jef.tools.Assert; import jef.tools.StringUtils; import com.github.geequery.codegen.Metadata.ColumnEx; import com.github.geequery.codegen.ast.JavaAnnotation; import com.github.geequery.codegen.ast.JavaConstructor; import com.github.geequery.codegen.ast.JavaContainer; import com.github.geequery.codegen.ast.JavaField; import com.github.geequery.codegen.ast.JavaUnit; /** * 从数据库表生成JEF的Entity类 * 指定数据库表,自动生成表对应的DataObject. * @author Administrator */ public class EntityGenerator { private String basePackage="jef.generated.dataobject"; private DatabaseDialect profile; private String entityBaseClass=DataObject.class.getName(); private MetaProvider provider; private File srcFolder=new File("src1"); private String includePattern; private String[] excludePatter; private int maxTables = 900; private EntityProcessorCallback callback; public File generateOne(String tablename,String entityName,String tableComment) throws SQLException { File file= this.saveJavaSource(generateSource(tablename,entityName,tableComment)); LogUtil.show(file.getAbsolutePath()+" generated."); return file; } public String getEntityBaseClass() { return entityBaseClass; } public void setEntityBaseClass(String entityBaseClass) { this.entityBaseClass = entityBaseClass; } public JavaUnit generateSource(String tablename,String entityName,String tableComment) throws SQLException { if(profile==null){ LogUtil.warn("Db dialect not set,default dialect set to Oracle."); profile=AbstractDialect.getProfile("oracle"); } tablename=profile.getObjectNameToUse(tablename); //System.out.println(" Generating Class for table:"+tablename+"...."); if(entityName==null)entityName=DbUtils.underlineToUpper(tablename, true); JavaUnit java=new JavaUnit(basePackage,entityName); java.addComments("This class was generated by JEF according to the table in database."); java.addComments("You need to modify the type of primary key field, to the strategy your own."); if(StringUtils.isNotEmpty(tableComment)){ java.addComments("Table:"+tableComment); } JavaAnnotation anno=new JavaAnnotation(Table.class); anno.put("name", tablename); String schema=provider.getSchema(); if(StringUtils.isNotEmpty(schema)){ anno.put("schema", schema); } java.setAnnotation("@Entity",anno.toCode(java)); Metadata meta=provider.getTableMetadata(tablename); if(meta.getCustParams()!=null && meta.getCustParams().get("custAnnot") != null){ String _tmpCustAnnot = meta.getCustParams().get("custAnnot"); java.addAnnotation(_tmpCustAnnot); if(_tmpCustAnnot.indexOf("PartitionTable")>=0){ java.addImport(PartitionTable.class); java.addImport(PartitionKey.class); } if(_tmpCustAnnot.indexOf("KeyFunction")>=0){ java.addImport(KeyFunction.class); } } java.setExtends(entityBaseClass); Map<String,String> pkColumns =meta.getPkFieldAndColumnNames(); if(pkColumns.size()>0){ java.addImport(javax.persistence.Id.class); } if(callback!=null){ callback.init(meta,tablename,provider.getSchema(),tableComment,java); } //生成元模型 JavaContainer enumField=new JavaContainer("public enum Field implements jef.database.Field{","}"); enumField.setWrap(false); java.addRawBlock(enumField); //生成用于元模型的字段配置 List<JavaField> pkFields=new ArrayList<JavaField>(); for(Column c:meta.getColumns()){ String columnName=c.getColumnName(); boolean isPk=pkColumns.containsValue(columnName); ColumnType columnType; try{ columnType=c.toColumnType(profile); }catch(Exception e){ throw new RuntimeException("The column ["+tablename+":"+columnName+"] 's type is error:"+ e.getMessage()); } if(!isPk){//不是主键时,错误的配置要还原 if(columnType.getClass()==ColumnType.AutoIncrement.class){ columnType=((AutoIncrement)columnType).toNormalType(); }else if(columnType.getClass()==ColumnType.GUID.class){ columnType=((GUID)columnType).toNormalType(); } } if(pkColumns.size()==1 && isPk){ //如果是单一主键,则修改为特定的JEF字段类型 if(columnType.getClass()==ColumnType.Int.class){ if(c.getColumnSize()==0)c.setColumnSize(8); columnType=new ColumnType.AutoIncrement(c.getColumnSize()); }else if(columnType.getClass()==ColumnType.Varchar.class){ if(((Varchar)columnType).getLength()>=32){ columnType=new ColumnType.GUID(); } } columnType.setNullable(false); //主键列不允许为空 } String[] annonation=getFieldAnnotation(java,columnName,columnType,isPk,c); String initValue=null; Class<?> clz=null; String fieldName; if(c instanceof ColumnEx){ fieldName=((ColumnEx) c).getFieldName(); clz=((ColumnEx) c).getJavaType(); initValue=((ColumnEx) c).getInitValue(); }else{ fieldName=columnToField(columnName); } if(clz==null)clz=columnType.getDefaultJavaType(); JavaField field=new JavaField(clz, fieldName); field.setModifiers(Modifier.PRIVATE); field.addAnnotation(annonation); field.addComments(StringUtils.trimToNull(c.getRemarks())); if(initValue!=null)field.setInitValue(initValue); java.addFieldWithGetterAndSetter(field); if(isPk)pkFields.add(field); if(enumField.contentSize()>0){ enumField.addContent(","+field.getName()); }else{ enumField.addContent(field.getName()); } if(callback!=null){ callback.addField(java,field,c,columnType); } } java.addImport(javax.persistence.Column.class); java.addImport(javax.persistence.Entity.class); //生成默认的构造器和主键构造器 JavaConstructor c1=new JavaConstructor(); java.addMethod(c1.getKey(),c1); if(!pkFields.isEmpty()){ JavaConstructor c2=new JavaConstructor(); for(JavaField field:pkFields){ c2.addparam(field.getType(), field.getName(),0); c2.addContent(StringUtils.concat("this.",field.getName()," = ", field.getName(),";")); } java.addMethod(c2.getKey(),c2); } if(callback!=null){ callback.finish(java); } return java; } private String columnToField(String columnName) { if(callback==null){ return DbUtils.underlineToUpper(columnName.toLowerCase(),false); }else{ return callback.columnToField(columnName); } } public File saveJavaSource(JavaUnit java){ try { if(srcFolder!=null){ File f=java.saveToSrcFolder(srcFolder,"UTF-8",OverWrittenMode.AUTO); return f; } } catch (IOException e) { LogUtil.exception(e); } return null; } //生成默认的annonation protected String[] getFieldAnnotation(JavaUnit java,String columnName,ColumnType column,boolean isPk,Column columnDef) { List<String> result=new ArrayList<String>(); Map<String,Object> anno=column.toJpaAnnonation(); Boolean b = null; if(columnDef instanceof ColumnEx){ ColumnEx ex=(ColumnEx)columnDef; b=ex.getGenerated(); String customAnno=StringUtils.trimToNull(ex.getAnnotation()); if(customAnno!=null) result.add(customAnno); } boolean isGenerated=false; StringBuilder sb=new StringBuilder(); for(Iterator<String> iter=anno.keySet().iterator();iter.hasNext();){ String key=iter.next(); if(key.startsWith("@")){ Object v=anno.get(key); String annoStr=(v==null)?key:key+"("+v+")"; if("@GeneratedValue".equals(key)){ if(Boolean.FALSE.equals(b)){//强行不做generate continue; }else{ java.addImport(javax.persistence.GenerationType.class); java.addImport(javax.persistence.GeneratedValue.class); } isGenerated=true; }else if("@Lob".equals(key)){ java.addImport(javax.persistence.Lob.class); } result.add(annoStr); }else{ if(sb.length()>0)sb.append(","); sb.append(key).append("="); Object v=anno.get(key); if(Number.class.isAssignableFrom(v.getClass())){ sb.append(anno.get(key)); }else if(Boolean.class==v.getClass()){ sb.append(v.toString()); }else{ sb.append("\"").append(anno.get(key)).append("\""); } } } //如果强行要求generated Class<?> type=column.getDefaultJavaType(); if(Boolean.TRUE.equals(b) && isGenerated==false){ java.addImport(javax.persistence.GenerationType.class); java.addImport(javax.persistence.GeneratedValue.class); if(type==String.class){ result.add("@GeneratedValue(strategy=GenerationType.IDENTITY)"); }else if(type==Long.class || type==Integer.class || type==Integer.TYPE || type==Long.TYPE){ result.add("@GeneratedValue(strategy=GenerationType.SEQUENCE)"); } } if(isPk){ if(!result.contains("@Id")){ result.add("@Id"); } } result.add("@Column(name=\""+columnName+"\","+sb.toString()+")"); return result.toArray(new String[result.size()]); } public void generateSchema() throws SQLException{ Assert.notNull(provider); RegexpNameFilter filter=new RegexpNameFilter(includePattern,excludePatter); int n=0; List<TableInfo> tables=provider.getTables(); if(callback!=null){ callback.setTotal(tables.size()); } for(TableInfo table:tables){ String tableName=table.getName(); if(filter.accept(tableName)){ try { generateOne(tableName,null,table.getRemarks()); } catch (SQLException e) { LogUtil.exception(e); } n++; } if(n>=maxTables)break; } LogUtil.show(n+" Class Mapping to Table are generated."); } public void generate(CommentEntry... strings) { Assert.notNull(provider); int limit=500; int n=0; for(CommentEntry table: strings){ try { generateOne(table.getKey(),null,table.getValue()); } catch (SQLException e) { LogUtil.exception(e); } n++; if(n>=limit)break; } LogUtil.show(strings.length+" Class Mapping to Table are generated."); } public void setProfile(DatabaseDialect profile) { this.profile = profile; } public void setSrcFolder(File srcFolder) { this.srcFolder = srcFolder; } public void setProvider(MetaProvider provider) { this.provider = provider; } public void setIncludePattern(String includePattern) { this.includePattern = includePattern; } public void addExcludePatter(String pattern) { if(pattern==null){ this.excludePatter=new String[]{pattern}; } this.excludePatter = (String[]) ArrayUtils.add(this.excludePatter, pattern); } public int getMaxTables() { return maxTables; } public void setMaxTables(int maxTables) { this.maxTables = maxTables; } public String getBasePackage() { return basePackage; } public void setBasePackage(String basePackage) { this.basePackage = basePackage; } public void setCallback(EntityProcessorCallback callback) { this.callback = callback; } }