Created
January 3, 2015 14:15
-
-
Save wendal/14a0a84b4dbf280e6faa to your computer and use it in GitHub Desktop.
基于XML配置NutDao的Entity, 未测试代码, 正式代码会出现在nutz主库或nutzmore项目.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.nutz.dao.impl.entity.xml; | |
public class IotUser { | |
private long id; | |
private String name; | |
private int age; | |
public int getAge() { | |
return age; | |
} | |
public void setAge(int age) { | |
this.age = age; | |
} | |
private String location; | |
public long getId() { | |
return id; | |
} | |
public void setId(long id) { | |
this.id = id; | |
} | |
public String getName() { | |
return name; | |
} | |
public void setName(String name) { | |
this.name = name; | |
} | |
public String getLocation() { | |
return location; | |
} | |
public void setLocation(String location) { | |
this.location = location; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<xsd:schema xmlns="http://nutzam.com/schema/entities" targetNamespace="http://nutzam.com/schema/entities" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> | |
<xsd:element name="nutz-mapping"> | |
<xsd:complexType> | |
<xsd:sequence> | |
<xsd:element name="entity" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:sequence> | |
<xsd:element name="id" maxOccurs="1" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:sequence> | |
<xsd:element name="coldefine" maxOccurs="1" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:attribute name="type" type="xsd:string"></xsd:attribute> | |
<xsd:attribute name="width" type="xsd:integer"></xsd:attribute> | |
<xsd:attribute name="precision" type="xsd:integer"></xsd:attribute> | |
<xsd:attribute name="notNull" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="unsigned" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="auto" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="customType"></xsd:attribute> | |
<xsd:attribute name="insert" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="update" type="xsd:boolean"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="prev" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:sequence> | |
<xsd:element name="sql" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="el" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:sequence> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="next" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:sequence> | |
<xsd:element name="sql" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="el" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:sequence> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:sequence> | |
<xsd:attribute name="column" type="xsd:string"></xsd:attribute> | |
<xsd:attribute name="auto" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="name" type="xsd:string"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="name" maxOccurs="1" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:sequence> | |
<xsd:element name="coldefine" maxOccurs="1" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:attribute name="type" type="xsd:string"></xsd:attribute> | |
<xsd:attribute name="width" type="xsd:integer"></xsd:attribute> | |
<xsd:attribute name="precision" type="xsd:integer"></xsd:attribute> | |
<xsd:attribute name="notNull" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="unsigned" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="auto" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="customType"></xsd:attribute> | |
<xsd:attribute name="insert" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="update" type="xsd:boolean"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="prev" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:sequence> | |
<xsd:element name="sql" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="el" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:sequence> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="next" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:sequence> | |
<xsd:element name="sql" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="el" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:sequence> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:sequence> | |
<xsd:attribute name="column" type="xsd:string"></xsd:attribute> | |
<xsd:attribute name="name" type="xsd:string"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="field" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:sequence> | |
<xsd:element name="coldefine" maxOccurs="1" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:attribute name="type" type="xsd:string"></xsd:attribute> | |
<xsd:attribute name="width" type="xsd:integer"></xsd:attribute> | |
<xsd:attribute name="precision" type="xsd:integer"></xsd:attribute> | |
<xsd:attribute name="notNull" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="unsigned" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="auto" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="customType"></xsd:attribute> | |
<xsd:attribute name="insert" type="xsd:boolean"></xsd:attribute> | |
<xsd:attribute name="update" type="xsd:boolean"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="prev" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:sequence> | |
<xsd:element name="sql" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="el" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:sequence> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="next" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:sequence> | |
<xsd:element name="sql" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="el" minOccurs="0" maxOccurs="unbounded"> | |
<xsd:complexType> | |
<xsd:attribute name="db"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:sequence> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:sequence> | |
<xsd:attribute name="column" type="xsd:string"></xsd:attribute> | |
<xsd:attribute name="name" type="xsd:string" use="required"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="one" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:attribute name="name" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="target" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="field" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="key" type="xsd:string"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="many" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:attribute name="name" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="target" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="field" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="key" type="xsd:string"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="manymany" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:attribute name="name" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="target" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="relation" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="from" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="to" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="key" type="xsd:string"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
<xsd:element name="index" maxOccurs="unbounded" minOccurs="0"> | |
<xsd:complexType> | |
<xsd:attribute name="name" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="fields" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="unique" type="xsd:boolean"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:sequence> | |
<xsd:attribute name="type" type="xsd:string" use="required"></xsd:attribute> | |
<xsd:attribute name="table" type="xsd:string"></xsd:attribute> | |
<xsd:attribute name="view" type="xsd:string"></xsd:attribute> | |
<xsd:attribute name="comment" type="xsd:string"></xsd:attribute> | |
<xsd:attribute name="pks" type="xsd:string"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:sequence> | |
<xsd:attribute name="package" type="xsd:string"></xsd:attribute> | |
</xsd:complexType> | |
</xsd:element> | |
</xsd:schema> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?xml version="1.0" encoding="UTF-8"?> | |
<p:nutz-mapping package="org.nutz.dao.impl.entity.xml" xmlns:p="http://nutzam.com/schema/entities" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://nutzam.com/schema/entities nutz-dao-0.1.xsd "> | |
<entity comment="" pks="" table="t_iot_user" type="IotUser" view=""> | |
<id/> | |
<name/> | |
<field name="age"></field> | |
<field column="loc" name="location"> | |
<coldefine auto="true" customType="" insert="true" notNull="true" precision="0" type="" unsigned="true" update="true" width="0"/> | |
</field> | |
<one field="level" name="level" target="IotUserLevel"/> | |
<many field="userId" name="devices" target=""/> | |
<manymany name="devices" from="uid" relation="user_device" target="IotDevice" to="did"/> | |
<index fields="age" name="age" unique="true"/> | |
</entity> | |
</p:nutz-mapping> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package org.nutz.dao.impl.entity.xml; | |
import java.io.IOException; | |
import java.io.InputStream; | |
import java.lang.reflect.Field; | |
import java.sql.Connection; | |
import java.util.ArrayList; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Map; | |
import java.util.Map.Entry; | |
import java.util.concurrent.ConcurrentHashMap; | |
import javax.sql.DataSource; | |
import javax.xml.parsers.DocumentBuilder; | |
import javax.xml.parsers.ParserConfigurationException; | |
import org.nutz.dao.DB; | |
import org.nutz.dao.DaoException; | |
import org.nutz.dao.entity.Entity; | |
import org.nutz.dao.entity.EntityMaker; | |
import org.nutz.dao.entity.MacroType; | |
import org.nutz.dao.entity.MappingField; | |
import org.nutz.dao.entity.annotation.ColType; | |
import org.nutz.dao.impl.EntityHolder; | |
import org.nutz.dao.impl.entity.FieldMacroInfo; | |
import org.nutz.dao.impl.entity.NutEntity; | |
import org.nutz.dao.impl.entity.NutEntityIndex; | |
import org.nutz.dao.impl.entity.field.ManyLinkField; | |
import org.nutz.dao.impl.entity.field.ManyManyLinkField; | |
import org.nutz.dao.impl.entity.field.NutMappingField; | |
import org.nutz.dao.impl.entity.field.OneLinkField; | |
import org.nutz.dao.impl.entity.info.LinkInfo; | |
import org.nutz.dao.impl.entity.macro.ElFieldMacro; | |
import org.nutz.dao.impl.entity.macro.SqlFieldMacro; | |
import org.nutz.dao.jdbc.JdbcExpert; | |
import org.nutz.dao.jdbc.Jdbcs; | |
import org.nutz.dao.sql.Pojo; | |
import org.nutz.lang.Lang; | |
import org.nutz.lang.Strings; | |
import org.nutz.lang.Xmls; | |
import org.nutz.log.Log; | |
import org.nutz.log.Logs; | |
import org.nutz.resource.NutResource; | |
import org.nutz.resource.Scans; | |
import org.nutz.trans.Trans; | |
import org.w3c.dom.Document; | |
import org.w3c.dom.Element; | |
import org.xml.sax.SAXException; | |
/** | |
* 基于XML配置Entity | |
* @author wendal(wendal1985@gmail.com) | |
* | |
*/ | |
@SuppressWarnings({"unchecked", "rawtypes"}) | |
public class XmlEntityMaker implements EntityMaker { | |
private static final Log log = Logs.get(); | |
Map<String, Entity> map = new ConcurrentHashMap<String, Entity>(); | |
DocumentBuilder builder; | |
private DataSource datasource; | |
private JdbcExpert expert; | |
private EntityHolder holder; | |
protected Map<String, List<Element>> pendingLinks = new ConcurrentHashMap<String, List<Element>>(); | |
public XmlEntityMaker(DataSource datasource, JdbcExpert expert, EntityHolder holder) throws ParserConfigurationException { | |
builder = Lang.xmls(); | |
this.datasource = datasource; | |
this.expert = expert; | |
this.holder = holder; | |
} | |
public <T> Entity<T> make(Class<T> type) { | |
return map.get(type); // 注意, 这里是单纯从缓存中获取已有的Entity, 因为是基于XML的 | |
} | |
public void setPaths(String ... paths) throws IOException, SAXException { | |
for (String path : paths) { | |
addPath(path); | |
} | |
try { | |
verify(); | |
} catch (DaoException e) { | |
log.info("some relation pending are not complete", e); | |
} | |
} | |
public void addPath(String path) throws IOException, SAXException { | |
List<NutResource> files = Scans.me().scan(path, ".xml$"); | |
if (files.isEmpty()) | |
return; | |
for (NutResource resource : files) { | |
log.debug("load entity xml --> " + resource.getName()); | |
add(resource.getInputStream()); | |
} | |
} | |
public void add(InputStream ins) throws IOException, SAXException { | |
add(builder.parse(ins)); | |
} | |
public void add(Document document) { | |
document.normalizeDocument(); | |
Element top = document.getDocumentElement(); | |
if (!top.getNodeName().endsWith("nutz-mapping")) { // 没有nutz-mapping, 自然没啥好说的了 | |
log.info("skip xml without nutz-mapping"); | |
return; | |
} | |
String topPackageName = top.getAttribute("package"); | |
for (Element ele : Xmls.children(top, "entity")) { // 一个XML中允许包含多个entity描述 | |
addXmlEntity(ele, topPackageName); | |
} | |
} | |
public void addXmlEntity(final Element ele, String topPackageName) { | |
String type = ele.getAttribute("type"); | |
if (Strings.isBlank(type)) // xsd有约束,这里再检查一次 | |
throw new DaoException("entity without type!!"); | |
Class<?> klass = null; | |
try { | |
klass = loadClass(topPackageName, type); // 尝试载入对应的类 | |
} catch (ClassNotFoundException e) { | |
throw new DaoException("entity type ClassNotFound : " + type, e); | |
} | |
NutEntity<?> en = new NutEntity(klass); | |
String tableName = null; | |
if (Strings.isBlank(ele.getAttribute("table"))) { | |
tableName = Strings.lowerWord(klass.getSimpleName(), '_'); | |
log.warnf("No @Table found, fallback to use table name='%s' for type '%s'", tableName, klass.getName()); | |
} else { | |
tableName = ele.getAttribute("table"); | |
} | |
String viewName = Strings.isBlank(ele.getAttribute("view")) ? tableName : ele.getAttribute("view"); | |
en.setTableName(tableName); | |
en.setViewName(viewName); | |
// 表注解 | |
String tableComment = ele.getAttribute("comment"); | |
if (!Strings.isBlank(tableComment)) | |
en.setTableComment(tableComment); | |
// TODO 支持default, readonly 注解所对应的xml配置 | |
// 先塞进去, 主要是为了避免1对1的自我映射 | |
holder.set(en); | |
map.put(type, en); | |
// 下面开始处理字段,索引,等等 | |
for (Element e : Xmls.children(ele)) { | |
String ename = e.getNodeName(); | |
if ("id".equals(ename)) { | |
addField(en, e, true, false); | |
} else if ("name".equals(ename)) { | |
addField(en, e, false, true); | |
} else if ("field".equals(ename)) { | |
addField(en, e, false, false); | |
} else if ("index".equals(ename)) { | |
String indexName = e.getAttribute("name"); | |
if (Strings.isBlank(indexName)) { | |
throw new DaoException("index must have a name, entity=" + type); | |
} | |
String indexFields = e.getAttribute("fields"); | |
if (Strings.isBlank(indexFields)) { | |
throw new DaoException("index must have fields, entity=" + type); | |
} | |
boolean indexUnique = "true".equals(e.getAttribute("unique")); | |
NutEntityIndex eIndex = new NutEntityIndex(); | |
eIndex.setName(ename); | |
eIndex.setUnique(indexUnique); | |
String[] names = Strings.splitIgnoreBlank(indexFields, ","); | |
for (String fieldName : names) { | |
MappingField field = en.getField(fieldName); | |
if (field == null) | |
throw new DaoException("index refer not-exist field, entity=" + type + ", field=" + fieldName); | |
en.addIndex(eIndex); | |
} | |
} else if ("one".equals(ename) || "many".equals(ename) || "manymany".equals(ename)) { | |
String target = e.getAttribute("target"); | |
Class<?> targetClass = null;; | |
try { | |
targetClass = loadClass(topPackageName, target); | |
} catch (ClassNotFoundException e1) { | |
throw new DaoException("relation ClassNotFound entity=" + en.getType().getName() + ", relation class=" + target); | |
} | |
Entity relationEntity = map.get(targetClass); | |
if (relationEntity == null) { | |
List<Element> list = pendingLinks.get(en.getType().getName()); | |
if (list == null) { | |
list = new ArrayList<Element>(); | |
pendingLinks.put(en.getType().getName(), list); | |
log.debug("add pending relation mapping " + e); | |
} | |
e.setAttribute("fullClassName", targetClass.getName()); | |
list.add(e); | |
} else { | |
addRelation(en, relationEntity, e); | |
} | |
} | |
} | |
// 处理一下复合主键 | |
String pks = ele.getAttribute("pks"); | |
if (!Strings.isBlank(pks)) { | |
String[] tmp = Strings.splitIgnoreBlank(pks, ","); | |
en.checkCompositeFields(tmp); | |
} | |
if (null != datasource && null != expert) { | |
_checkupEntityFieldsWithDatabase(en); | |
} | |
} | |
public void verify() throws DaoException { | |
if (pendingLinks.isEmpty()) | |
return; | |
for (Entry<String, List<Element>> pending : pendingLinks.entrySet()) { | |
try { | |
NutEntity en = (NutEntity) map.get(loadClass(null, pending.getKey())); | |
Iterator<Element> it = pending.getValue().iterator(); | |
while (it.hasNext()) { | |
Element element = it.next(); | |
NutEntity relation = (NutEntity) map.get(loadClass(null, element.getAttribute("fullClassName"))); | |
addRelation(en, relation, element); | |
it.remove(); | |
} | |
} catch (ClassNotFoundException e) { | |
throw Lang.impossible(); | |
} | |
pendingLinks.remove(pending.getKey()); | |
} | |
} | |
protected void addRelation(NutEntity<?> en, Entity relationEntity, Element e) { | |
LinkInfo info = new LinkInfo(); | |
info.name = e.getAttribute("name"); | |
try { | |
info.fieldType = en.getMirror().getField(info.name).getType(); | |
} catch (NoSuchFieldException e1) { | |
throw new DaoException("field not exist. entity=" + en.getType() + ",field=" + info.name); | |
} | |
info.injecting = en.getMirror().getInjecting(info.name); | |
info.ejecting = en.getMirror().getEjecting(info.name); | |
String rname = e.getNodeName(); | |
if ("one".equals(rname) || "many".equals(rname)) { | |
String fieldName = e.getAttribute("field"); | |
MappingField mf = en.getField(fieldName); | |
if (fieldName == null || mf == null) { | |
throw new DaoException(String.format("%s <--> %s by field(%s) , but not exist", en.getType(), relationEntity.getType(), fieldName)); | |
} | |
String key = e.getAttribute("key"); | |
MappingField mfKey = null; | |
if (!Strings.isBlank(key)) { | |
mfKey = relationEntity.getField(key); | |
} else { | |
mfKey = mf.getTypeMirror().isIntLike() ? relationEntity.getIdField() : relationEntity.getNameField(); | |
} | |
if (mfKey == null) { | |
throw new DaoException(String.format("%s <--> %s by field(%s) , but not exist", en.getType(), relationEntity.getType(), mfKey)); | |
} | |
if ("one".equals(rname)) { | |
OneLinkField one = new OneLinkField(en, holder, info, relationEntity.getClass(), mf, mfKey); | |
en.addLinkField(one); | |
} else { | |
ManyLinkField many = new ManyLinkField(en, holder, info, relationEntity.getClass(), mf, mfKey); | |
en.addLinkField(many); | |
} | |
} else if ("manymany".equals(rname)) { | |
// 多对多 | |
String from = e.getAttribute("from"); | |
String to = e.getAttribute("to"); | |
String relation = e.getAttribute("relation"); | |
String key = e.getAttribute("key"); | |
ManyManyLinkField manymany = new ManyManyLinkField(en, holder, info, relationEntity.getType(), from, to, relation, key); | |
en.addLinkField(manymany); | |
} | |
} | |
protected void addField(NutEntity en, Element ele, boolean isId, boolean isName) { | |
NutMappingField mf = new NutMappingField(en); | |
// 处理name属性 | |
String name = ele.getAttribute("name"); | |
if (isId) { | |
mf.setAsId(); | |
if (!"false".equals(ele.getAttribute("auto"))) | |
mf.setAsAutoIncreasement(); | |
if (Strings.isBlank(name)) | |
mf.setName("id"); | |
else | |
mf.setName(name); | |
} else if (isName) { | |
mf.setAsName(); | |
if (Strings.isBlank(name)) | |
mf.setName("name"); | |
else | |
mf.setName(name); | |
} else { | |
if (Strings.isBlank(name)) | |
throw new DaoException("field must have a name attribute, entity=" + en.getType().getName()); | |
mf.setName(name); | |
} | |
name = mf.getName(); | |
try { | |
Field field = en.getMirror().getField(name); | |
mf.setType(field.getType()); | |
} catch (NoSuchFieldException e) { | |
throw new DaoException("not such field in entity=" + en.getType().getName() + ", field=" + name); | |
} | |
// 处理column属性 | |
String columnName = ele.getAttribute("column"); | |
if (!Strings.isBlank(columnName)) | |
mf.setColumnName(columnName); | |
else | |
mf.setColumnName(name); | |
// 处理comment属性 | |
if (!Strings.isBlank(ele.getAttribute("comment"))) { | |
mf.setColumnComment(ele.getAttribute("comment")); | |
en.setHasColumnComment(true); | |
} | |
// 处理一下coldefine, prev, next节点 | |
boolean flag = true; | |
for (Element e : Xmls.children(ele)) { | |
String ename = e.getNodeName(); | |
if ("coldefine".equalsIgnoreCase(ename)) { | |
flag = false; | |
addColDefine(mf, e); | |
} else if ("prev".equalsIgnoreCase(ename)) { | |
_makeMacro(en, mf, e, true); | |
} else if ("next".equals(ename)) { | |
_makeMacro(en, mf, e, false); | |
} | |
} | |
if (flag) { | |
Jdbcs.guessEntityFieldColumnType(mf); | |
} | |
// 字段值的适配器 | |
if (expert != null) | |
mf.setAdaptor(expert.getAdaptor(mf)); | |
mf.setInjecting(en.getMirror().getInjecting(name)); | |
mf.setEjecting(en.getMirror().getEjecting(name)); | |
en.addMappingField(mf); | |
} | |
protected void addColDefine(NutMappingField mf, Element ele) { | |
if (hasAttr(ele, "type")) | |
mf.setColumnType(ColType.valueOf(ele.getAttribute("type"))); | |
if (hasAttr(ele, "width")) | |
mf.setWidth(Integer.parseInt(ele.getAttribute("width"))); | |
if (mf.getWidth() == 0 && mf.getColumnType() == ColType.VARCHAR) | |
mf.setWidth(50); | |
if (hasAttr(ele, "precision")) | |
mf.setPrecision(Integer.parseInt(ele.getAttribute("precision"))); | |
if ("true".equals(ele.getAttribute("notNull"))) | |
mf.setAsNotNull(); | |
if ("true".equals(ele.getAttribute("unsigned"))) | |
mf.setAsUnsigned(); | |
// 无视auto设置 | |
// -------------- | |
if (hasAttr(ele, "customType")) | |
mf.setCustomDbType(ele.getAttribute("customType")); | |
if ("false".equals(ele.getAttribute("insert"))) | |
mf.setInsert(false); | |
if ("false".equals(ele.getAttribute("update"))) | |
mf.setUpdate(false); | |
} | |
protected boolean hasAttr(Element ele, String attrName) { | |
return !Strings.isBlank(ele.getAttribute(attrName)); | |
} | |
protected void _makeMacro(NutEntity en, NutMappingField mf, Element ele, boolean isPrev) { | |
List<FieldMacroInfo> list = new ArrayList<FieldMacroInfo>(); | |
for(Element e : Xmls.children(ele)) { | |
String nodeName = e.getNodeName(); | |
DB db = hasAttr(e, "db") ? DB.OTHER : DB.valueOf(e.getAttribute("db")); | |
if ("sql".equals(nodeName)) { | |
FieldMacroInfo sql = new FieldMacroInfo(MacroType.SQL, db, Xmls.getText(e)); | |
list.add(sql); | |
} else if ("el".equals(nodeName)) { | |
FieldMacroInfo el = new FieldMacroInfo(MacroType.EL, db, Xmls.getText(e)); | |
list.add(el); | |
} | |
}; | |
if (isPrev) | |
en.addBeforeInsertMacro(__macro(mf, list)); | |
else | |
en.addAfterInsertMacro(__macro(mf, list)); | |
} | |
private void _checkupEntityFieldsWithDatabase(NutEntity<?> en) { | |
Connection conn = null; | |
try { | |
conn = Trans.getConnectionAuto(datasource); | |
expert.setupEntityField(conn, en); | |
} | |
catch (Exception e) { | |
if (log.isDebugEnabled()) | |
log.debugf("Fail to setup '%s'(%s) by DB, because: (%s)'%s'", | |
en.getType().getName(), | |
en.getTableName(), | |
e.getClass().getName(), | |
e.getMessage()); | |
} | |
finally { | |
Trans.closeConnectionAuto(conn); | |
} | |
} | |
private Pojo __macro(MappingField ef, List<FieldMacroInfo> infoList) { | |
FieldMacroInfo theInfo = null; | |
// 根据当前数据库,找到合适的宏 | |
for (FieldMacroInfo info : infoList) { | |
if (DB.OTHER == info.getDb()) { | |
theInfo = info; | |
} else if (info.getDb().name().equalsIgnoreCase(expert.getDatabaseType())) { | |
theInfo = info; | |
break; | |
} | |
} | |
// 如果找到,增加 | |
if (null != theInfo) { | |
if (theInfo.isEl()) | |
return new ElFieldMacro(ef, theInfo.getValue()); | |
else | |
return new SqlFieldMacro(ef, theInfo.getValue()); | |
} | |
return null; | |
} | |
protected Class<?> loadClass(String topPackageName, String type) throws ClassNotFoundException { | |
try { | |
return Class.forName(type); | |
} catch (ClassNotFoundException e) { | |
if (!Strings.isBlank(topPackageName)) | |
return Class.forName(topPackageName + "." + type); | |
throw e; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment