欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

给grails添加text映射支持

程序员文章站 2022-03-14 14:13:38
...
在grails中,domain class的String字段总是被映射成varchar,当然可以自己写xml映射文件解决这个问题,不过没有一劳永逸的解决方法了吗?于是开始搜索grails的论坛,发现这个特性还没有实现,开发人员倒是给出了一个issue:在constraints中实现type约束: propertyname(type:"text"),很郁闷了,还是自己来修改一下grails的源代码吧.
由于要在constraints中添加type约束,那么需要实现一个可以识别type的约束类,如下(在org.codehaus.groovy.grails.validation.ConstrainedProperty中):
先添加一个约束类字符串的声明, 反正他也不会用在validate,就在校验处理的时候什么也不作好了:
public static final String MAPPING_TYPE_CONSTRAINT = "type";
记得把这个类添加到map中
constraints.put(MAPPING_TYPE_CONSTRAINT, MappingTypeConstraint.class);

static class MappingTypeConstraint extends AbstractConstraint {
private String mapping_type;

public boolean supports(Class type) {
if (type == null)
return false;
return String.class.isAssignableFrom(type);
}

/*
* (non-Javadoc)
*
* @see org.codehaus.groovy.grails.validation.ConstrainedProperty.AbstractConstraint#setParameter(java.lang.Object)
*/
public void setParameter(Object constraintParameter) {
if (!(constraintParameter instanceof Comparable))
throw new IllegalArgumentException(
"Parameter for constraint ["
+ MAPPING_TYPE_CONSTRAINT
+ "] of property ["
+ constraintPropertyName
+ "] of class ["
+ constraintOwningClass
+ "] must implement the interface [java.lang.Comparable]");

this.mapping_type = (String) constraintParameter;
super.setParameter(constraintParameter);
}

public String getType() {
return this.mapping_type;
}

public String getName() {
return MAPPING_TYPE_CONSTRAINT;
}

protected void processValidate(Object target, Object propertyValue,
Errors errors) {
}
}

还要添加两个方法:
public Comparable getType() {
MappingTypeConstraint c = (MappingTypeConstraint) this.appliedConstraints
.get(MAPPING_TYPE_CONSTRAINT);
if (c == null) {
Range r = getRange();
if (r == null) {
return null;
} else {
return r.getFrom();
}
}
return c.getType();
}

public void setType(String type) {
if (!String.class.isInstance(propertyType)) {
throw new MissingPropertyException(
"Mapping type constraint can only be applied to a String property",
MAPPING_TYPE_CONSTRAINT, owningClass);
}

Constraint c = (Constraint) this.appliedConstraints
.get(MAPPING_TYPE_CONSTRAINT);
if (type == null) {
this.appliedConstraints.remove(MAPPING_TYPE_CONSTRAINT);
} else {
if (c != null) {
c.setParameter(type);
} else {
c = new MatchesConstraint();
c.setOwningClass(this.owningClass);
c.setPropertyName(this.propertyName);
c.setParameter(type);
this.appliedConstraints.put(MAPPING_TYPE_CONSTRAINT, c);
}
}
}
再添加个方法,偷懒点,只考虑"text"这种映射, 实际上我也只需要"text"映射:
public boolean hasMapTypeConstraints() {
return appliedConstraints.containsKey(MAPPING_TYPE_CONSTRAINT);
}
好了,前期准备工作基本上做好了,
然后去org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsDomainBinder
修改一下bindSimpleValue方法就ok了:

private static void bindSimpleValue(GrailsDomainClassProperty grailsProp, SimpleValue simpleValue,Mappings mappings) {
// set type

simpleValue.setTypeName(grailsProp.getType().getName());

//添加text映射支持
Map cs = (Map)grailsProp.getDomainClass().getConstrainedProperties();
if (cs != null) {
ConstrainedProperty cp = (ConstrainedProperty)cs.get(grailsProp.getName());
if (cp != null && cp.hasMapTypeConstraints()) {
simpleValue.setTypeName(Hibernate.TEXT.getName());

System.out.println("TEXT Mapping: for =>" + grailsProp.getName());
}

}


Table table = simpleValue.getTable();
Column column = new Column();
if(grailsProp.isManyToOne())
column.setNullable(false);

column.setValue(simpleValue);
bindColumn(grailsProp, column);

if(table != null) table.addColumn(column);

simpleValue.addColumn(column);
}

ok,重新打包放到grails的dist目录下面,这样我们就可以在grails的domainclass中使用这样的约束:
def constraints = {
content(length:10..20000,blank:false, type:"text")
}
于是content的类型就映射到了Hibernate.Text上面去了.而不是原先的varchar