net.sf.json.JSONException: Struts 2中的层级有环

net.sf.json.JSONException: There is a cycle in the hierarchy in Struts 2

我正在使用实现 ModelDriven 的 Struts 2 class。我能够从 jQuery 传递数据并将数据保存在数据库中。

当我尝试取回数据并将其传回 jQuery 时,我不确定为什么它在 jQuery 中不可用。我确定我在基本流程中遗漏了一些东西。

这是我的操作class:

public HttpHeaders index() {
    model = projectService.getProjectDetails(project.getUserID());
    return new DefaultHttpHeaders("success").setLocationId("");
} 

@Override
public Object getModel() {
    return project;
}

public Project getProject() {
    return project;
}

public void setProject(Project project) {
    this.project = project;
}

这是我的 jQuery:

function getProjectDetails() {
    var userID = localStorage.getItem('userID');
    var request = $.ajax({
        url : '/SUH/project.json',
        data : {
            userID : userID
        },
        dataType : 'json',
        type : 'GET',
        async : true
    });

    request.done(function(data) {
        console.log(JSON.stringify(data));
        $.each(data, function(index, element) {
            console.log('element project--->' + index + ":" + element);
            
        });
    });

    request.fail(function(jqXHR, textStatus) {
        console.log('faik');
    });
}

Action class 中的模型对象具有所有可用数据,但我尝试 return 模型或项目对象,但两者均无效。

默认情况下Struts2 REST 插件使用json-lib 序列化您的bean。如果您使用 ModelDriven,那么它会在处理结果时直接访问您的模型。由于您在请求 URL 中使用扩展 .json,因此内容类型处理程序由扩展选择。应该是JsonLibHandler.

如果 obj 是数组或列表,则此处理程序使用 JSONArray.fromObject(obj),否则使用 JSONObject.fromObject(obj) 来获取可以序列化并写入响应的 JSONObejct

objgetModel() 返回的值,在您的情况下它将是 project

因为 JsonLibHandler 使用默认值 JsonConfig 你不能从要序列化的 bean 中排除属性,除非它们是 public 字段。

json-lib 的以下功能可由 JsonConfig 提供支持:

  • Cycle detection, there are two default strategies (default throws an exception), you can register your own
  • Skip transient fields when serailizing to JSON (default=don't skip) Skip JAP @Transient annotated methods when serailizing to JSON (default=don't skip)
  • Exclude bean properties and/or map keys when serailizing to JSON (default=['class','metaClass','declaringClass'])
  • Filters provide a finer detail for excluding/including properties when serializing to JSON or transforming back to Java

您可以找到这个 code snippets 允许您排除一些属性。

Exclude properties

String str = "{'string':'JSON', 'integer': 1, 'double': 2.0, 'boolean': true}";  
JsonConfig jsonConfig = new JsonConfig();  
jsonConfig.setExcludes( new String[]{ "double", "boolean" } );  
JSONObject jsonObject = (JSONObject) JSONSerializer.toJSON( str, jsonConfig );  
assertEquals( "JSON", jsonObject.getString("string") );        
assertEquals( 1, jsonObject.getInt("integer") );        
assertFalse( jsonObject.has("double") );     
assertFalse( jsonObject.has("boolean") );     

Exclude properties (with filters)

String str = "{'string':'JSON', 'integer': 1, 'double': 2.0, 'boolean': true}";  
JsonConfig jsonConfig = new JsonConfig();  
jsonConfig.setJsonPropertyFilter( new PropertyFilter(){    
   public boolean apply( Object source, String name, Object value ) {    
      if( "double".equals(value) || "boolean".equals(value) ){    
         return true;    
      }    
      return false;    
   }    
});    
JSONObject jsonObject = (JSONObject) JSONSerializer.toJSON( str, jsonConfig );  
assertEquals( "JSON", jsonObject.getString("string") );        
assertEquals( 1, jsonObject.getInt("integer") );        
assertFalse( jsonObject.has("double") );     
assertFalse( jsonObject.has("boolean") );

但是您可以选择使用自己的 ContentTypeHandler 来覆盖默认值。

另一种方法是使用 Jackson 库来处理请求。如文档页面所述:Use Jackson framework as JSON ContentTypeHandler.

The default JSON Content Handler is build on top of the JSON-lib. If you prefer to use the Jackson framework for JSON serialisation, you can configure the JacksonLibHandler as Content Handler for your json requests.

First you need to add the jackson dependency to your web application by downloading the jar file and put it under WEB-INF/lib or by adding following xml snippet to your dependencies section in the pom.xml when you are using maven as build system.

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-jaxrs</artifactId>
    <version>1.9.13</version>
</dependency>

Now you can overwrite the Content Handler with the Jackson Content Handler in the struts.xml:

<bean type="org.apache.struts2.rest.handler.ContentTypeHandler" name="jackson" class="org.apache.struts2.rest.handler.JacksonLibHandler"/>
<constant name="struts.rest.handlerOverride.json" value="jackson"/>

<!-- Set to false if the json content can be returned for any kind of http method -->
<constant name="struts.rest.content.restrictToGET" value="false"/> 

<!-- Set encoding to UTF-8, default is ISO-8859-1 -->
<constant name="struts.i18n.encoding" value="UTF-8"/>

之后就可以使用@JsonIgnore注解了。