我的问题很长......所以,请耐心等待:)
我正在使用 ExtJS 4 中的模型,但我在关联方面遇到了一些问题,因此我创建了一个函数来为我执行自动模型创建。假设我需要解析以下 JSON:
{
"success": true,
"total": 28,
"itens": [{
"id":1,
"nome":"ACRE",
"sigla":"AC",
"pais":{
"id":31,
"nome":"BRASIL",
"sigla":"BR"
}
},{
"id":2,
"nome":"ALAGOAS",
"sigla":"AL",
"pais":{
"id":31,
"nome":"BRASIL",
"sigla":"BR"
}
}, ...]
}
itens 代表拥有国家(巴西葡萄牙语中的 País)的省(巴西葡萄牙语中的 Estados)。我尝试使用 ExtJS 关联,但我认为它像 Java 关系一样工作,我错了。好吧,对于这个 JSON,我有这些 Java 类和这些 Ext 模型(模型也是使用提供的函数创建的)。
派斯.java
@Entity
// named queries here...
public class Pais implements Serializable {
@Id
@GeneratedValue
private Long id;
@NotNull
@NotEmpty
@Length( max = 100 )
private String nome;
@NotNull
@NotEmpty
@Column( unique = true )
@Length( min = 2, max = 4 )
private String sigla;
// getters, setters, equals, hashCode and toString here
}
Estado.java
@Entity
// named queries here...
public class Estado implements Serializable {
@Id
@GeneratedValue
private Long id;
@NotNull
@NotEmpty
@Length( max = 100 )
private String nome;
@NotNull
@NotEmpty
@Column( unique = true )
@Length( min = 2, max = 4 )
private String sigla;
@NotNull
@ManyToOne
private Pais pais;
// getters, setters, equals, hashCode and toString here
}
创建模型的函数
Ext.ns( "Uteis" );
// other utility functions here...
Uteis.createModel = function( modelData ) {
var fields = modelData.fields;
var processedFields = [];
var normalFields = [];
var relationFields = [];
for ( var i in fields ) {
if ( fields[i].type ) {
switch ( fields[i].type ) {
case "auto":
case "string":
case "int":
case "float":
case "boolean":
case "date":
normalFields.push( fields[i] );
break;
default:
var relationField = fields[i];
var prefix = relationField.name + ".";
var modelInstance = Ext.create( relationField.type );
modelInstance.fields.each( function( item, index, length ) {
var newField = {};
// I used this sintax to make possible create only some fields
// if I need in the future.
newField["name"] = prefix + item.name;
newField["type"] = item.type.type;
newField["convert"] = item.convert;
newField["dateFormat"] = item.dateFormat;
newField["defaultValue"] = item.defaultValue;
newField["mapping"] = item.mapping;
newField["persist"] = item.persist;
newField["sortDir"] = item.sortDir;
newField["sortType"] = item.sortType;
newField["useNull"] = item.useNull;
relationFields.push( newField );
});
break;
}
} else {
normalFields.push( fields[i] );
}
}
processedFields = normalFields.concat( relationFields );
// debugging code
/*console.log( "*** " + modelData.name );
for ( var i in processedFields ) {
console.log( processedFields[i] );
}*/
Ext.define( modelData.name, {
extend: "Ext.data.Model",
fields: processedFields
});
};
使用函数创建模型
Uteis.createModel({
name: "Modelos.Pais",
fields: [
{ name: "id", type: "int" },
{ name: "nome", type: "string" },
{ name: "sigla", type: "string" }
]
});
Uteis.createModel({
name: "Modelos.Estado",
fields: [
{ name: "id", type: "int" },
{ name: "nome", type: "string" },
{ name: "sigla", type: "string" },
{ name: "pais", type: "Modelos.Pais" } // <= references the model created above
]
});
上面的代码与此相对应。我创建了自动创建嵌套数据字段的函数(因为我说的关联问题)。
Ext.define( "Modelos.Pais", {
extend: "Ext.data.Model",
fields: [
{ name: "id", type: "int" },
{ name: "nome", type: "string" },
{ name: "sigla", type: "string" }
]
});
Ext.define( "Modelos.Estado", {
extend: "Ext.data.Model",
fields: [
{ name: "id", type: "int" },
{ name: "nome", type: "string" },
{ name: "sigla", type: "string" },
{ name: "pais.id", type: "int" },
{ name: "pais.nome", type: "string" },
{ name: "pais.sigla", type: "string" }
]
});
好的,这些模型(使用我的 createModel 函数创建)非常适合我的 JsonStores。到现在为止,Java 端的所有映射关联都不是空的,所以,我的商店总是有嵌套数据要处理。现在,我必须处理一些可以具有空关联的实体,我的问题开始了。需要处理这种情况的存储不起作用(存储操作中抛出异常,说字段为空)。我正在使用 Gson 从我的实体创建 JSON。它的默认行为是不序列化空字段,它们将在客户端未定义,所以我认为如果我序列化空字段(发送空值)将使 Ext 实现空字段而不尝试处理它。为此,我使用此代码创建 Gson:
Gson gson = new GsonBuilder().serializeNulls().create();
好的,现在正在生成带有空关联的 JSON,但 Ext 继续抱怨。我尝试使用字段映射和 defaultValue 配置但没有成功。为了使事情更简单,让我们使用 Estados 和 Países(Privinces 和 Country)的示例,其中 Pais 不再是 @NotNull。带有 null pais 的 JSON 如下所示:
{
"success": true,
"total": 28,
"itens": [{
"id":1,
"nome":"ACRE",
"sigla":"AC",
"pais":null // <= here
},{
"id":2,
"nome":"ALAGOAS",
"sigla":"AL",
"pais":{ // this is not null
"id":31,
"nome":"BRASIL",
"sigla":"BR"
}
}, ...]
}
使用此代码,pais.id、pais.nome 和 pais.sigla 字段将不可用,因为 pais 属性为空。所以,我的问题是:当某些字段为空或未定义时,如何让商店忽略它们?我已经尝试寻找没有成功的解决方案......非常感谢!
编辑:在服务器端考虑了整个晚上的一些可能的解决方案后,我在最后 15 分钟内实现了一个解决方案,但我绝对不喜欢它......它是一种在使用之前遍历每个对象“对象树”的反射方法Gson 将默认值设置为空字段。它正在工作,但是 JSON 变得不必要地太大了。遍历方法:
/**
* A method to traverse the object tree and set "default" values to null fields.
*
* @param target The object to be inspected.
*/
public static void traverseAndSetDefaultValue( Object target ) {
try {
for ( Field f : target.getClass().getDeclaredFields() ) {
// ok to change...
f.setAccessible( true );
// is null? so create something
if ( f.get( target ) == null ) {
// new instance of the current field
Object newInstance = null;
// it needs to traverse to the next level?
boolean okToTraverse = false;
switch ( f.getType().getSimpleName() ) {
case "Byte":
case "Short":
case "Integer":
newInstance = 0;
break;
case "Long":
newInstance = 0L;
break;
case "Float":
newInstance = 0F;
break;
case "Double":
newInstance = 0D;
break;
case "Character":
newInstance = '\0';
break;
case "Boolean":
newInstance = Boolean.FALSE;
break;
case "String":
newInstance = "";
break;
case "List":
newInstance = new ArrayList();
break;
case "Set":
newInstance = new HashSet();
break;
default:
// calling the default constructor for no
// "default" types
newInstance = f.getType().newInstance();
okToTraverse = true;
break;
}
f.set( target, newInstance );
if ( okToTraverse ) {
traverseAndSetDefaultValue( newInstance );
}
}
}
} catch ( IllegalAccessException | InstantiationException exc ) {
exc.printStackTrace();
}
}
我想知道您对此有何看法...谢谢!
编辑2:你好。我放弃!:) 我将使用我在上面发布的解决方案。我找到了一些补丁来改善与模型和网格的关系。我测试了它们,但空字段的问题仍然存在(至少错误消失了)。好的,现在是继续开发的时候了。应用程序完成后,我将回到这个问题以尝试改进我的解决方案。谢谢!