JSON 도구 학습 기록 -- FastJSON 순환 참조 문제

16992 단어 JSONjavaWEB 실전
JSON 도구 학습 기록 - FastJSON 순환 참조 문제
태그 (공백 구분): fastjson
최근 에 다른 사람의 프로젝트 를 바탕 으로 2 차 개발 을 하 다가 순환 인용 문제 에 부 딪 혔 다. 쉽게 말 하면 A 는 B, B 는 C, C 는 A 를 인용 했다. 그러면 제 이 슨 을 바 꾸 면 끊임없이 전환 된다. 더욱 복잡 한 상황 에서 A 는 B, B 에서 A 의 집합 을 인용 했다. 예 를 들 어 광고 유형 을 인용 했다 고 광고 유형 에 해당 유형의 소속 광고 가 있다.
1. 상황 구성
이런 것 을 쌍방 향 인용 이 라 고도 하 는데 개인 적 으로 이런 디자인 자체 가 합 리 적 이지 않다 고 생각 하기 때문에 당연히 구체 적 인 사용 장면 을 봐 야 한다.
광고 종류:
/**
 * @author Niu Li
 * @date 2016/8/12
 */
public class ADEntity {
    private int id;
    private String name;
    //          
    private ADTypeEntity adTypeEntity;

    public ADEntity(int id, String name, ADTypeEntity adTypeEntity) {
        this.id = id;
        this.name = name;
        this.adTypeEntity = adTypeEntity;
    }
//  get set
}

광고 실체 클래스:
import java.util.List;

/**
 * @author Niu Li
 * @date 2016/8/12
 */
public class ADTypeEntity {
    private int id;
    private String name;
    //        
    private List lists;
    //  get set
}

테스트 코드:
public class TestApp {
    public static void main(String[] args) {
        //      
        ADTypeEntity adTypeEntity = new ADTypeEntity();
        adTypeEntity.setId(1);
        adTypeEntity.setName("   ");
        //    
        ADEntity entity1 = new ADEntity(1," 1",adTypeEntity);
        ADEntity entity2 = new ADEntity(2," 2",adTypeEntity);
        ADEntity entity3 = new ADEntity(3," 3",adTypeEntity);

        List lists = new ArrayList();
        lists.add(entity1);
        lists.add(entity2);
        lists.add(entity3);
        //    
        adTypeEntity.setLists(lists);

        String result = JSON.toJSONString(entity1);
        System.out.println(result);
    }
}

결 과 는 양 방향 인용 이 4. 567914 로 바 뀌 었 음 을 볼 수 있다.
{
  "adTypeEntity": {
    "id": 1,
    "lists": [
      {
        "$ref": "$"
      },
      {
        "adTypeEntity": {
          "$ref": "$.adTypeEntity"
        },
        "id": 2,
        "name": " 2"
      },
      {
        "adTypeEntity": {
          "$ref": "$.adTypeEntity"
        },
        "id": 3,
        "name": " 3"
      }
    ],
    "name": "   "
  },
  "id": 1,
  "name": " 1"
}

2. 해결 방법
두 가지 해결 방법 은 순환 인용 이 있 는 곳 에 이 필드 를 걸 러 내 는 것 이다.
1. 필터 방식 은 JSONfield 주석 을 사용 하여 이 필드 가 json 으로 변환 되 지 않 음 을 설명 할 수 있 습 니 다.
    @JSONField(serialize = false)
    private List lists;

결 과 를 얻다
{
  "adTypeEntity": {
    "id": 1,
    "name": "   "
  },
  "id": 1,
  "name": " 1"
}

2. 사용자 정의 변환 필드
 SimplePropertyPreFilter filter = new SimplePropertyPreFilter(ADTypeEntity.class,"id","name");
        String result = JSON.toJSONString(entity1,filter);

이것 은 ADTypeEntity 클래스 에 대해 id 와 name 필드 만 직렬 화 한 다 는 것 을 나타 낸다. 그러면 list 집합 인용 을 제외 하고 얻 은 결 과 는 위 와 같다.
3. 정상 변환 규칙 다단 계 필터
다음으로 전송:http://www.cnblogs.com/sandyfog/articles/3679804.html
fastjson 은 일부 인터페이스 에서 지정 한 필터 속성 을 실현 할 수 있 습 니 다. 필터 의 본질은 fastjson 이 매번 직렬 화 필드 를 할 때마다 Apply 방법 을 통 해 판단 합 니 다. Apply 가 true 로 돌아 갈 때 만 직렬 화 되 기 때문에 속성 명 에 따라 자 유 롭 게 걸 러 낼 수 있 습 니 다.
다음은 Property PreFilter 인 터 페 이 스 를 실현 하고 name 값 에 따라 판정 을 배제 합 니 다.
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.serializer.JSONSerializer;
import com.alibaba.fastjson.serializer.PropertyPreFilter;
import com.alibaba.fastjson.serializer.SerializerFeature;

import java.util.HashMap;
import java.util.Map;

/**
 * @date 2016/8/17
 */
public class ComplexPropertyPreFilter implements PropertyPreFilter {
    private Map, String[]> includes = new HashMap<>();
    private Map, String[]> excludes = new HashMap<>();

    static {
        //            
        JSON.DEFAULT_GENERATE_FEATURE |= SerializerFeature.DisableCircularReferenceDetect.getMask();
    }

    public ComplexPropertyPreFilter() {

    }

    public ComplexPropertyPreFilter(Map, String[]> includes) {
        super();
        this.includes = includes;
    }

    public boolean apply(JSONSerializer serializer, Object source, String name) {

        //    。    
        if (source == null) {
            return true;
        }

        //                 
        Class> clazz = source.getClass();

        //        、         ,        
        //             
        for (Map.Entry, String[]> item : this.excludes.entrySet()) {
            // isAssignableFrom(),              
            if (item.getKey().isAssignableFrom(clazz)) {
                String[] strs = item.getValue();

                //        name       
                if (isHave(strs, name)) {
                    return false;
                }
            }
        }

        //                       
        if (this.includes.isEmpty()) {
            return true;
        }

        //        
        //             
        for (Map.Entry, String[]> item : this.includes.entrySet()) {
            // isAssignableFrom(),              
            if (item.getKey().isAssignableFrom(clazz)) {
                String[] strs = item.getValue();
                //        name       
                if (isHave(strs, name)) {
                    return true;
                }
            }
        }

        return false;
    }

    /*
     *         ,             ,              
     */
    public static boolean isHave(String[] strs, String s) {

        for (int i = 0; i < strs.length; i++) {
            //                             
            if (strs[i].equals(s)) {
                //         ,      
                return true;
            }
        }

        //      false
        return false;
    }

    public Map, String[]> getIncludes() {
        return includes;
    }

    public void setIncludes(Map, String[]> includes) {
        this.includes = includes;
    }

    public Map, String[]> getExcludes() {
        return excludes;
    }

    public void setExcludes(Map, String[]> excludes) {
        this.excludes = excludes;
    }
}

자기 코드 에 사용 되 는 필터
 Pageable pageable = new Pageable(page,rows);
        Page promotionPages = promotionService.findPage(pageable);

        String[] promotionFilters = {"id", "name","title","image","endDate","priceExpression","memberRanks"};
        String[] memberFilter = {"id","name"};
        String[] pageFilter = {"pageNumber","pageSize","content","total","totalPages"};
        Map,String[]> mapFilter = new HashMap<>();
        mapFilter.put(Promotion.class,promotionFilters);
        mapFilter.put(MemberRank.class,memberFilter);
        mapFilter.put(Page.class,pageFilter);

        ResultData result = new ResultData.Builder(ResultVo.OK)
                .setData(APPJsonUtil.toJsonObject(mapFilter,null,promotionPages))
                .builder();

json 도구
 /**
     *          jsonObject,    
     * @param object
     * @return
     */
    public static JSONObject toJsonObject(Map, String[]> includes,Map, String[]> excludes, Object object){
        ComplexPropertyPreFilter filter = new ComplexPropertyPreFilter();
        if (excludes != null) {
            filter.setExcludes(excludes);
        }
        if (includes != null) {
            filter.setIncludes(includes);
        }
        String result = JSON.toJSONString(object, filter);
        return JSON.parseObject(result);
    }

좋은 웹페이지 즐겨찾기