org.codelibs.fess.api.json.JsonApiManager.java Source code

Java tutorial

Introduction

Here is the source code for org.codelibs.fess.api.json.JsonApiManager.java

Source

/*
 * Copyright 2009-2015 the CodeLibs Project and the Others.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the License for the specific language
 * governing permissions and limitations under the License.
 */

package org.codelibs.fess.api.json;

import java.io.IOException;
import java.io.StringWriter;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import jp.sf.fess.suggest.entity.SpellCheckResponse;
import jp.sf.fess.suggest.entity.SuggestResponse;
import jp.sf.fess.suggest.entity.SuggestResponse.SuggestResponseList;

import org.apache.commons.lang.StringEscapeUtils;
import org.codelibs.core.CoreLibConstants;
import org.codelibs.core.util.StringUtil;
import org.codelibs.fess.Constants;
import org.codelibs.fess.WebApiException;
import org.codelibs.fess.api.BaseApiManager;
import org.codelibs.fess.api.WebApiManager;
import org.codelibs.fess.api.WebApiRequest;
import org.codelibs.fess.api.WebApiResponse;
import org.codelibs.fess.db.allcommon.CDef;
import org.codelibs.fess.entity.FieldAnalysisResponse;
import org.codelibs.fess.entity.PingResponse;
import org.codelibs.fess.entity.PingResponse.Target;
import org.codelibs.fess.service.SearchService;
import org.codelibs.fess.util.ComponentUtil;
import org.codelibs.fess.util.FacetResponse;
import org.codelibs.fess.util.FacetResponse.Field;
import org.codelibs.fess.util.MoreLikeThisResponse;
import org.codelibs.fess.util.WebApiUtil;
import org.seasar.struts.util.RequestUtil;
import org.seasar.struts.util.ResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class JsonApiManager extends BaseApiManager implements WebApiManager {

    private static final Logger logger = LoggerFactory.getLogger(JsonApiManager.class);

    protected String jsonPathPrefix = "/json";

    @Override
    public boolean matches(final HttpServletRequest request) {
        if (Constants.FALSE.equals(ComponentUtil.getCrawlerProperties().getProperty(Constants.WEB_API_JSON_PROPERTY,
                Constants.TRUE))) {
            return false;
        }

        final String servletPath = request.getServletPath();
        return servletPath.startsWith(jsonPathPrefix);
    }

    @Override
    public void process(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) throws IOException, ServletException {
        final String formatType = request.getParameter("type");
        switch (getFormatType(formatType)) {
        case SEARCH:
            processSearchRequest(request, response, chain);
            break;
        case LABEL:
            processLabelRequest(request, response, chain);
            break;
        case SUGGEST:
            processSuggestRequest(request, response, chain);
            break;
        case SPELLCHECK:
            processSpellCheckRequest(request, response, chain);
            break;
        case ANALYSIS:
            processAnalysisRequest(request, response, chain);
            break;
        case HOTSEARCHWORD:
            processHotSearchWordRequest(request, response, chain);
            break;
        case FAVORITE:
            processFavoriteRequest(request, response, chain);
            break;
        case FAVORITES:
            processFavoritesRequest(request, response, chain);
            break;
        case PING:
            processPingRequest(request, response, chain);
            break;
        default:
            writeJsonResponse(99, StringUtil.EMPTY, "Not found.");
            break;
        }
    }

    protected void processPingRequest(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) {
        final SearchService searchService = ComponentUtil.getSearchService();
        int status;
        final StringBuilder buf = new StringBuilder(1000);
        String errMsg = null;
        try {
            final PingResponse pingResponse = searchService.ping();
            status = pingResponse.getStatus();
            buf.append("\"result\":[");
            boolean appended = false;
            for (final Target target : pingResponse.getTargets()) {
                if (appended) {
                    buf.append(',');
                } else {
                    appended = true;
                }
                buf.append("{\"status\":");
                buf.append(target.getStatus());
                buf.append(",\"url\":\"");
                buf.append(escapeJson(target.getUrl()));
                buf.append("\",\"queryTime\":");
                buf.append(target.getQueryTime());
                buf.append(",\"searchTime\":");
                buf.append(target.getSearchTime());
                buf.append("}");
            }
            buf.append(']');
        } catch (final Exception e) {
            status = 9;
            errMsg = e.getMessage();
            if (errMsg == null) {
                errMsg = e.getClass().getName();
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to process a ping request.", e);
            }
        }

        writeJsonResponse(status, buf.toString(), errMsg);
    }

    protected void processSearchRequest(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) {
        int status = 0;
        String errMsg = StringUtil.EMPTY;
        String query = null;
        final StringBuilder buf = new StringBuilder(1000);
        request.setAttribute(Constants.SEARCH_LOG_ACCESS_TYPE, CDef.AccessType.Json);
        final String queryId = request.getParameter("queryId");
        try {
            chain.doFilter(new WebApiRequest(request, SEARCH_API), new WebApiResponse(response));
            WebApiUtil.validate();
            query = WebApiUtil.getObject("searchQuery");
            final String execTime = WebApiUtil.getObject("execTime");
            final String queryTime = WebApiUtil.getObject("queryTime");
            final String searchTime = WebApiUtil.getObject("searchTime");
            final String pageSize = WebApiUtil.getObject("pageSize");
            final String currentPageNumber = WebApiUtil.getObject("currentPageNumber");
            final String allRecordCount = WebApiUtil.getObject("allRecordCount");
            final String allPageCount = WebApiUtil.getObject("allPageCount");
            final List<Map<String, Object>> documentItems = WebApiUtil.getObject("documentItems");
            final FacetResponse facetResponse = WebApiUtil.getObject("facetResponse");
            final MoreLikeThisResponse moreLikeThisResponse = WebApiUtil.getObject("moreLikeThisResponse");

            buf.append("\"query\":");
            buf.append(escapeJson(query));
            buf.append(",\"execTime\":");
            buf.append(execTime);
            buf.append(",\"queryTime\":");
            buf.append(queryTime);
            buf.append(",\"searchTime\":");
            buf.append(searchTime);
            buf.append(',');
            if (StringUtil.isNotBlank(queryId)) {
                buf.append("\"queryId\":");
                buf.append(escapeJson(queryId));
                buf.append(',');
            }
            buf.append("\"pageSize\":");
            buf.append(pageSize);
            buf.append(',');
            buf.append("\"pageNumber\":");
            buf.append(currentPageNumber);
            buf.append(',');
            buf.append("\"recordCount\":");
            buf.append(allRecordCount);
            buf.append(',');
            buf.append("\"pageCount\":");
            buf.append(allPageCount);
            if (!documentItems.isEmpty()) {
                buf.append(',');
                buf.append("\"result\":[");
                boolean first1 = true;
                for (final Map<String, Object> document : documentItems) {
                    if (!first1) {
                        buf.append(',');
                    } else {
                        first1 = false;
                    }
                    buf.append('{');
                    boolean first2 = true;
                    for (final Map.Entry<String, Object> entry : document.entrySet()) {
                        final String name = entry.getKey();
                        if (StringUtil.isNotBlank(name) && entry.getValue() != null
                                && ComponentUtil.getQueryHelper().isApiResponseField(name)) {
                            if (!first2) {
                                buf.append(',');
                            } else {
                                first2 = false;
                            }
                            buf.append(escapeJson(name));
                            buf.append(':');
                            buf.append(escapeJson(entry.getValue()));
                        }
                    }
                    buf.append('}');
                }
                buf.append(']');
            }
            if (facetResponse != null && facetResponse.hasFacetResponse()) {
                // facet field
                if (facetResponse.getFieldList() != null) {
                    buf.append(',');
                    buf.append("\"facetField\":[");
                    boolean first1 = true;
                    for (final Field field : facetResponse.getFieldList()) {
                        if (!first1) {
                            buf.append(',');
                        } else {
                            first1 = false;
                        }
                        buf.append("{\"name\":");
                        buf.append(escapeJson(field.getName()));
                        buf.append(",\"result\":[");
                        boolean first2 = true;
                        for (final Map.Entry<String, Long> entry : field.getValueCountMap().entrySet()) {
                            if (!first2) {
                                buf.append(',');
                            } else {
                                first2 = false;
                            }
                            buf.append("{\"value\":");
                            buf.append(escapeJson(entry.getKey()));
                            buf.append(",\"count\":");
                            buf.append(entry.getValue());
                            buf.append('}');
                        }
                        buf.append(']');
                        buf.append('}');
                    }
                    buf.append(']');
                }
                // facet query
                if (facetResponse.getQueryCountMap() != null) {
                    buf.append(',');
                    buf.append("\"facetQuery\":[");
                    boolean first1 = true;
                    for (final Map.Entry<String, Long> entry : facetResponse.getQueryCountMap().entrySet()) {
                        if (!first1) {
                            buf.append(',');
                        } else {
                            first1 = false;
                        }
                        buf.append("{\"value\":");
                        buf.append(escapeJson(entry.getKey()));
                        buf.append(",\"count\":");
                        buf.append(entry.getValue());
                        buf.append('}');
                    }
                    buf.append(']');
                }
            }
            if (moreLikeThisResponse != null && !moreLikeThisResponse.isEmpty()) {
                buf.append(',');
                buf.append("\"moreLikeThis\":[");
                boolean first = true;
                for (final Map.Entry<String, List<Map<String, Object>>> mltEntry : moreLikeThisResponse
                        .entrySet()) {
                    if (!first) {
                        buf.append(',');
                    } else {
                        first = false;
                    }
                    buf.append("{\"id\":");
                    buf.append(escapeJson(mltEntry.getKey()));
                    buf.append(",\"result\":[");
                    boolean first1 = true;
                    for (final Map<String, Object> document : mltEntry.getValue()) {
                        if (!first1) {
                            buf.append(',');
                        } else {
                            first1 = false;
                        }
                        buf.append('{');
                        boolean first2 = true;
                        for (final Map.Entry<String, Object> entry : document.entrySet()) {
                            if (StringUtil.isNotBlank(entry.getKey()) && entry.getValue() != null) {
                                if (!first2) {
                                    buf.append(',');
                                } else {
                                    first2 = false;
                                }
                                buf.append(escapeJson(entry.getKey()));
                                buf.append(':');
                                buf.append(escapeJson(entry.getValue()));
                            }
                        }
                        buf.append('}');
                    }
                    buf.append("]}");
                }
                buf.append(']');
            }
        } catch (final Exception e) {
            status = 1;
            errMsg = e.getMessage();
            if (errMsg == null) {
                errMsg = e.getClass().getName();
            }
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to process a search request.", e);
            }
        }

        writeJsonResponse(status, buf.toString(), errMsg);

    }

    protected void processLabelRequest(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) {
        int status = 0;
        String errMsg = StringUtil.EMPTY;
        final StringBuilder buf = new StringBuilder(255);
        try {
            final List<Map<String, String>> labelTypeItems = ComponentUtil.getLabelTypeHelper()
                    .getLabelTypeItemList();
            buf.append("\"recordCount\":");
            buf.append(labelTypeItems.size());
            if (!labelTypeItems.isEmpty()) {
                buf.append(',');
                buf.append("\"result\":[");
                boolean first1 = true;
                for (final Map<String, String> labelMap : labelTypeItems) {
                    if (!first1) {
                        buf.append(',');
                    } else {
                        first1 = false;
                    }
                    buf.append("{\"label\":");
                    buf.append(escapeJson(labelMap.get(Constants.ITEM_LABEL)));
                    buf.append(", \"value\":");
                    buf.append(escapeJson(labelMap.get(Constants.ITEM_VALUE)));
                    buf.append('}');
                }
                buf.append(']');
            }
        } catch (final Exception e) {
            status = 1;
            errMsg = e.getMessage();
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to process a label request.", e);
            }
        }

        writeJsonResponse(status, buf.toString(), errMsg);

    }

    protected void processSuggestRequest(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) {

        int status = 0;
        String errMsg = StringUtil.EMPTY;
        final StringBuilder buf = new StringBuilder(255);
        try {
            chain.doFilter(new WebApiRequest(request, SUGGEST_API), new WebApiResponse(response));
            WebApiUtil.validate();
            final Integer suggestRecordCount = WebApiUtil.getObject("suggestRecordCount");
            final List<SuggestResponse> suggestResultList = WebApiUtil.getObject("suggestResultList");
            final List<String> suggestFieldName = WebApiUtil.getObject("suggestFieldName");

            buf.append("\"recordCount\":");
            buf.append(suggestRecordCount);

            if (suggestResultList.size() > 0) {
                buf.append(',');
                buf.append("\"result\":[");
                boolean first1 = true;
                for (int i = 0; i < suggestResultList.size(); i++) {

                    final SuggestResponse suggestResponse = suggestResultList.get(i);

                    for (final Map.Entry<String, List<String>> entry : suggestResponse.entrySet()) {
                        final String fn = suggestFieldName.get(i);
                        if (!first1) {
                            buf.append(',');
                        } else {
                            first1 = false;
                        }

                        final SuggestResponseList srList = (SuggestResponseList) entry.getValue();

                        buf.append("{\"token\":");
                        buf.append(escapeJson(entry.getKey()));
                        buf.append(", \"fn\":");
                        buf.append(escapeJson(fn));
                        buf.append(", \"startOffset\":");
                        buf.append(Integer.toString(srList.getStartOffset()));
                        buf.append(", \"endOffset\":");
                        buf.append(Integer.toString(srList.getEndOffset()));
                        buf.append(", \"numFound\":");
                        buf.append(Integer.toString(srList.getNumFound()));
                        buf.append(", ");
                        buf.append("\"result\":[");
                        boolean first2 = true;
                        for (final String value : srList) {
                            if (!first2) {
                                buf.append(',');
                            } else {
                                first2 = false;
                            }
                            buf.append(escapeJson(value));
                        }
                        buf.append("]}");
                    }

                }
                buf.append(']');
            }
        } catch (final Exception e) {
            if (e instanceof WebApiException) {
                status = ((WebApiException) e).getStatusCode();
            } else {
                status = 1;
            }
            errMsg = e.getMessage();
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to process a suggest request.", e);
            }
        }

        writeJsonResponse(status, buf.toString(), errMsg);

    }

    protected void processSpellCheckRequest(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) {

        int status = 0;
        String errMsg = StringUtil.EMPTY;
        final StringBuilder buf = new StringBuilder(255);
        try {
            chain.doFilter(new WebApiRequest(request, SPELLCHECK_API), new WebApiResponse(response));
            WebApiUtil.validate();
            final Integer spellCheckRecordCount = WebApiUtil.getObject("spellCheckRecordCount");
            final List<SpellCheckResponse> spellCheckResultList = WebApiUtil.getObject("spellCheckResultList");
            final List<String> spellCheckFieldName = WebApiUtil.getObject("spellCheckFieldName");

            buf.append("\"recordCount\":");
            buf.append(spellCheckRecordCount);

            if (spellCheckResultList.size() > 0) {
                buf.append(',');
                buf.append("\"result\":[");
                boolean first1 = true;
                for (int i = 0; i < spellCheckResultList.size(); i++) {

                    final SuggestResponse suggestResponse = spellCheckResultList.get(i);

                    for (final Map.Entry<String, List<String>> entry : suggestResponse.entrySet()) {
                        final String fn = spellCheckFieldName.get(i);
                        if (!first1) {
                            buf.append(',');
                        } else {
                            first1 = false;
                        }

                        final SuggestResponseList srList = (SuggestResponseList) entry.getValue();

                        buf.append("{\"token\":");
                        buf.append(escapeJson(entry.getKey()));
                        buf.append(", \"fn\":");
                        buf.append(escapeJson(fn));
                        buf.append(", \"startOffset\":");
                        buf.append(Integer.toString(srList.getStartOffset()));
                        buf.append(", \"endOffset\":");
                        buf.append(Integer.toString(srList.getEndOffset()));
                        buf.append(", \"numFound\":");
                        buf.append(Integer.toString(srList.getNumFound()));
                        buf.append(", ");
                        buf.append("\"result\":[");
                        boolean first2 = true;
                        for (final String value : srList) {
                            if (!first2) {
                                buf.append(',');
                            } else {
                                first2 = false;
                            }
                            buf.append(escapeJson(value));
                        }
                        buf.append("]}");
                    }

                }
                buf.append(']');
            }
        } catch (final Exception e) {
            if (e instanceof WebApiException) {
                status = ((WebApiException) e).getStatusCode();
            } else {
                status = 1;
            }
            errMsg = e.getMessage();
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to process a spellcheck request.", e);
            }
        }

        writeJsonResponse(status, buf.toString(), errMsg);

    }

    protected void processAnalysisRequest(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) {

        int status = 0;
        String errMsg = StringUtil.EMPTY;
        final StringBuilder buf = new StringBuilder(255);
        try {
            chain.doFilter(new WebApiRequest(request, ANALYSIS_API), new WebApiResponse(response));
            WebApiUtil.validate();
            final FieldAnalysisResponse fieldAnalysis = WebApiUtil.getObject("fieldAnalysis");

            buf.append("\"recordCount\":");
            buf.append(fieldAnalysis.size());

            if (fieldAnalysis.size() > 0) {
                buf.append(',');
                buf.append("\"result\":[");
                boolean first1 = true;
                for (final Map.Entry<String, Map<String, List<Map<String, Object>>>> fEntry : fieldAnalysis
                        .entrySet()) {
                    if (first1) {
                        first1 = false;
                    } else {
                        buf.append(',');
                    }
                    buf.append("{\"field\":").append(escapeJson(fEntry.getKey())).append(",\"analysis\":[");
                    boolean first2 = true;
                    for (final Map.Entry<String, List<Map<String, Object>>> aEntry : fEntry.getValue().entrySet()) {
                        if (first2) {
                            first2 = false;
                        } else {
                            buf.append(',');
                        }
                        buf.append("{\"name\":").append(escapeJson(aEntry.getKey())).append(",\"data\":[");
                        boolean first3 = true;
                        for (final Map<String, Object> dataMap : aEntry.getValue()) {
                            if (first3) {
                                first3 = false;
                            } else {
                                buf.append(',');
                            }
                            buf.append('{');
                            boolean first4 = true;
                            for (final Map.Entry<String, Object> dEntry : dataMap.entrySet()) {
                                final String key = dEntry.getKey();
                                final Object value = dEntry.getValue();
                                if (StringUtil.isNotBlank(key) && value != null) {
                                    if (first4) {
                                        first4 = false;
                                    } else {
                                        buf.append(',');
                                    }
                                    buf.append(escapeJson(key)).append(':').append(escapeJson(value));
                                }
                            }
                            buf.append('}');
                        }
                        buf.append("]}");
                    }
                    buf.append("]}");
                }
                buf.append(']');
            }
        } catch (final Exception e) {
            if (e instanceof WebApiException) {
                status = ((WebApiException) e).getStatusCode();
            } else {
                status = 1;
            }
            errMsg = e.getMessage();
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to process a suggest request.", e);
            }
        }

        writeJsonResponse(status, buf.toString(), errMsg);

    }

    protected void processHotSearchWordRequest(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) {

        int status = 0;
        String errMsg = StringUtil.EMPTY;
        final StringBuilder buf = new StringBuilder(255);
        try {
            chain.doFilter(new WebApiRequest(request, HOT_SEARCH_WORD_API), new WebApiResponse(response));
            WebApiUtil.validate();
            final List<String> hotSearchWordList = WebApiUtil.getObject("hotSearchWordList");

            buf.append("\"result\":[");
            boolean first1 = true;
            for (final String word : hotSearchWordList) {
                if (!first1) {
                    buf.append(',');
                } else {
                    first1 = false;
                }
                buf.append(escapeJson(word));
            }
            buf.append(']');
        } catch (final Exception e) {
            if (e instanceof WebApiException) {
                status = ((WebApiException) e).getStatusCode();
            } else {
                status = 1;
            }
            errMsg = e.getMessage();
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to process a hotSearchWord request.", e);
            }
        }

        writeJsonResponse(status, buf.toString(), errMsg);

    }

    protected void processFavoriteRequest(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) {
        int status = 0;
        String body = null;
        String errMsg = null;
        try {
            chain.doFilter(new WebApiRequest(request, FAVORITE_API), new WebApiResponse(response));
            WebApiUtil.validate();

            body = "\"result\":\"ok\"";

        } catch (final Exception e) {
            if (e instanceof WebApiException) {
                status = ((WebApiException) e).getStatusCode();
            } else {
                status = 1;
            }
            errMsg = e.getMessage();
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to process a favorite request.", e);
            }
        }

        writeJsonResponse(status, body, errMsg);
    }

    protected void processFavoritesRequest(final HttpServletRequest request, final HttpServletResponse response,
            final FilterChain chain) {
        int status = 0;
        String body = null;
        String errMsg = null;

        try {
            chain.doFilter(new WebApiRequest(request, FAVORITES_API), new WebApiResponse(response));
            WebApiUtil.validate();
            final List<String> docIdList = WebApiUtil.getObject("docIdList");

            final StringBuilder buf = new StringBuilder();
            buf.append("\"num\":").append(docIdList.size());
            if (!docIdList.isEmpty()) {
                buf.append(", \"docIds\":[");
                for (int i = 0; i < docIdList.size(); i++) {
                    if (i > 0) {
                        buf.append(',');
                    }
                    buf.append(escapeJson(docIdList.get(i)));
                }
                buf.append(']');
            }
            body = buf.toString();
        } catch (final Exception e) {
            if (e instanceof WebApiException) {
                status = ((WebApiException) e).getStatusCode();
            } else {
                status = 1;
            }
            errMsg = e.getMessage();
            if (logger.isDebugEnabled()) {
                logger.debug("Failed to process a favorites request.", e);
            }
        }

        writeJsonResponse(status, body, errMsg);

    }

    protected void writeJsonResponse(final int status, final String body, final String errMsg) {
        final String callback = RequestUtil.getRequest().getParameter("callback");
        final boolean isJsonp = StringUtil.isNotBlank(callback);

        final StringBuilder buf = new StringBuilder(1000);
        if (isJsonp) {
            buf.append(escapeCallbackName(callback));
            buf.append('(');
        }
        buf.append("{\"response\":");
        buf.append("{\"version\":");
        buf.append(Constants.WEB_API_VERSION);
        buf.append(',');
        buf.append("\"status\":");
        buf.append(status);
        buf.append(',');
        if (status == 0) {
            buf.append(body);
        } else {
            buf.append("\"message\":");
            buf.append(escapeJson(errMsg));
        }
        buf.append('}');
        buf.append('}');
        if (isJsonp) {
            buf.append(')');
        }
        ResponseUtil.write(buf.toString(), "text/javascript+json", Constants.UTF_8);

    }

    protected String escapeCallbackName(final String callbackName) {
        return "/**/" + callbackName.replaceAll("[^0-9a-zA-Z_\\$\\.]", StringUtil.EMPTY);
    }

    protected String escapeJson(final Object obj) {
        if (obj == null) {
            return "null";
        }

        final StringBuilder buf = new StringBuilder(255);
        if (obj instanceof List<?>) {
            buf.append('[');
            boolean first = true;
            for (final Object child : (List<?>) obj) {
                if (first) {
                    first = false;
                } else {
                    buf.append(',');
                }
                buf.append(escapeJson(child));
            }
            buf.append(']');
        } else if (obj instanceof Map<?, ?>) {
            buf.append('{');
            boolean first = true;
            for (final Map.Entry<?, ?> entry : ((Map<?, ?>) obj).entrySet()) {
                if (first) {
                    first = false;
                } else {
                    buf.append(',');
                }
                buf.append(escapeJson(entry.getKey())).append(':').append(escapeJson(entry.getValue()));
            }
            buf.append('}');
        } else if (obj instanceof Integer || obj instanceof Long || obj instanceof Float || obj instanceof Double
                || obj instanceof Short) {
            buf.append(obj);
        } else if (obj instanceof Date) {
            final SimpleDateFormat sdf = new SimpleDateFormat(CoreLibConstants.DATE_FORMAT_ISO_8601_EXTEND);
            buf.append('\"').append(StringEscapeUtils.escapeXml(sdf.format(obj))).append('\"');
        } else {
            buf.append('\"').append(escapeJsonString(obj.toString())).append('\"');
        }
        return buf.toString();
    }

    protected String escapeJsonString(final String str) {

        final StringWriter out = new StringWriter(str.length() * 2);
        int sz;
        sz = str.length();
        for (int i = 0; i < sz; i++) {
            final char ch = str.charAt(i);

            // handle unicode
            if (ch > 0xfff) {
                out.write("\\u");
                out.write(hex(ch));
            } else if (ch > 0xff) {
                out.write("\\u0");
                out.write(hex(ch));
            } else if (ch > 0x7f) {
                out.write("\\u00");
                out.write(hex(ch));
            } else if (ch < 32) {
                switch (ch) {
                case '\b':
                    out.write('\\');
                    out.write('b');
                    break;
                case '\n':
                    out.write('\\');
                    out.write('n');
                    break;
                case '\t':
                    out.write('\\');
                    out.write('t');
                    break;
                case '\f':
                    out.write('\\');
                    out.write('f');
                    break;
                case '\r':
                    out.write('\\');
                    out.write('r');
                    break;
                default:
                    if (ch > 0xf) {
                        out.write("\\u00");
                        out.write(hex(ch));
                    } else {
                        out.write("\\u000");
                        out.write(hex(ch));
                    }
                    break;
                }
            } else {
                switch (ch) {
                case '"':
                    out.write("\\u0022");
                    break;
                case '\\':
                    out.write("\\u005C");
                    break;
                case '/':
                    out.write("\\u002F");
                    break;
                default:
                    out.write(ch);
                    break;
                }
            }
        }
        return out.toString();
    }

    private String hex(final char ch) {
        return Integer.toHexString(ch).toUpperCase();
    }

    public String getJsonPathPrefix() {
        return jsonPathPrefix;
    }

    public void setJsonPathPrefix(final String jsonPathPrefix) {
        this.jsonPathPrefix = jsonPathPrefix;
    }

}