SonarUtils.java 工具类:
public class SonarUtils { private static Logger logger = LoggerFactory.getLogger(SonarUtils.class); static String[] MEASURES_TO_GET = new String[]{"violations", "ncloc", "files", "duplicated_lines_density", "violations_density", "blocker_violations", "critical_violations", "major_violations", "minor_violations", "info_violations", "sqale_index", "sqale_debt_ratio", "comment_lines", "comment_lines_density", "public_undocumented_api", "public_documented_api_density", SonarQualityParam.COMPLEXITY.getType(), SonarQualityParam.TESTS.getType(), SonarQualityParam.TEST_ERRORS.getType(), SonarQualityParam.TEST_FAILURES.getType(), SonarQualityParam.TEST_EXECUTION_TIME.getType(), SonarQualityParam.LINES_TO_COVER.getType(), SonarQualityParam.UNCOVERED_LINES.getType(), SonarQualityParam.ALLLINES.getType(), SonarQualityParam.DUPLICATED_LINES.getType(), SonarQualityParam.LINE_COVERAGE.getType(), SonarQualityParam.COVERAGE.getType(), SonarQualityParam.SKIPPED_TESTS.getType(), SonarQualityParam.TEST_SUCCESS_DENSITY.getType()}; public static List<Measure> getallMeasures(String resourceKey,String sonarhost) { logger.info("The resourceKey is:" + resourceKey); // 用户名 String username = PropertiesReader.getProperty("sonar.userName"); // 密码 String password = PropertiesReader.getProperty("sonar.passWd"); Sonar sonar = Sonar.create(sonarhost, username, password); ResourceQuery query = ResourceQuery.createForMetrics(resourceKey, SonarQualityParam.convert2StringArray()); query.setIncludeTrends(true); Resource resource = sonar.find(query); // 循环遍历获取"violations", "lines" List<Measure> measureList = null; if (null != resource) { measureList = resource.getMeasures(); List<Measure> others = getOthers(resourceKey, sonarhost); if(CollectionUtils.isNotEmpty(others)){ if (CollectionUtils.isEmpty(measureList)) { measureList = others; } else { measureList.addAll(others); } } /*Map<String, String> targetMap = null; try { targetMap = httpRequest(sonarHost,resourceKey,*//*"new_coverage,ncloc"*//*"new_coverage,new_lines,new_sqale_debt_ratio,new_maintainability_rating"); } catch (Exception e) { logger.info("获取api出错,eem:{}",e.getMessage()); } if(null != targetMap){ Iterator<Entry<String, String>> iter = targetMap.entrySet().iterator(); while(iter.hasNext()){ Map.Entry<String, String> entry = (Entry<String, String>) iter.next(); if(null != entry.getValue()){ Measure measure = new Measure(); measure.setMetricKey(entry.getKey().toString()); measure.setValue(Double.parseDouble(new DecimalFormat("0.0").format(Double.parseDouble(entry.getValue().toString())))); measure.setFormattedValue(new DecimalFormat("0.0").format(Double.parseDouble(entry.getValue().toString()))); measureList.add(measure); } } }*/ } return measureList; } private static List<Measure> getOthers(String resourceKey,String sonarhost) { // 用户名 String username = PropertiesReader.getProperty("sonar.userName"); // 密码 String password = PropertiesReader.getProperty("sonar.passWd"); SonarMeasuresComponentClient.Builder builder = SonarMeasuresComponentClient.builder().url(sonarhost).login(username).password(password);//"http://sonar.cnsuning.com" SonarMeasuresComponentClient measuresComponentClient = builder.build(); IssueQuery query = IssueQuery.create(); query.urlParams().put("componentKey", resourceKey); query.urlParams().put("metricKeys", "new_uncovered_conditions,new_uncovered_lines,new_duplicated_blocks,new_lines_to_cover,bugs,files,new_bugs,new_vulnerabilities,new_code_smells,new_duplicated_lines,new_violations,uncovered_conditions,new_branch_coverage,new_coverage,new_lines,new_sqale_debt_ratio,new_maintainability_rating"); query.urlParams().put("additionalFields", "metrics,periods"); MeasuresComponent measuresComponent = measuresComponentClient.measuresComponentClient().find(query); return measuresComponent.getMeasures(); } /*public static Map<String, String> httpRequest(String sonarHost, String componentKey, String targets) throws Exception { *//* Map<String, Object> paramMap = new HashMap<String, Object>(); paramMap.put("componentKey", componentKey); paramMap.put("metricKeys", targets); paramMap.put("additionalFields", "metrics,periods");*//* List<String> targetList = Arrays.asList(targets.split(",")); Map<String, String> targetMap = new HashMap<String, String>(); String jsonStr = HttpRequest.sendGet(sonarHost + "/api/measures/component", "componentKey=" + componentKey + "&metricKeys=" + targets + "&additionalFields=metrics,periods"); //HttpHandler.request(sonarHost + "/api/measures/component", paramMap, new HashMap<String, String>(), HttpHandler.BodyType.BODY_TYPE_JSON, HttpHandler.MethodType.METHOD_TYPE_POST).getData(); JSONArray measures = JSONObject.fromObject(jsonStr).getJSONObject("component").getJSONArray("measures"); if (StringUtils.isNotBlank(jsonStr) && CollectionUtils.isNotEmpty(measures)) { for (int i = 0; i < measures.size(); i++) { JSONObject measure = measures.getJSONObject(i); if (null != measure.get("periods")) { String metric = measure.getString("metric"); JSONArray periods = measure.getJSONArray("periods"); for (String target : targetList) { if (StringUtils.equals(target, String.valueOf(metric)) && CollectionUtils.isNotEmpty(periods)) { for (int j = 0; j < periods.size(); j++) { JSONObject period = periods.getJSONObject(j); targetMap.put(metric + "_" + period.getInt("index"), period.getString("value")); } break; } } } } } return targetMap; }*/ /** * @param componentId * @return */ public static Collection<UserIssuesBO> getIssues(String componentId) { // Sonar参数地址 String sonarHost = PropertiesReader.getProperty("jenkins.sonar.host"); //String sonarHost = "http://10.37.87.244:9000"; // 用户名 String sonarUsername = PropertiesReader.getProperty("sonar.userName"); // 密码 String sonarPwd = PropertiesReader.getProperty("sonar.passWd"); SonarClient.Builder builder = SonarClient.builder().url(sonarHost).login(sonarUsername).password(sonarPwd);//"http://sonar.cnsuning.com" SonarClient sonarClient = builder.build(); Map<String, UserIssuesBO> result = new HashMap<String, UserIssuesBO>(); createUserIssues(sonarClient, 1, 500, componentId, result);//"AV2cwEligP6n2VFNN5AE" if (!result.isEmpty()) { return result.values(); } return new ArrayList(); } /** * @param sonarClient * @param page * @param pageSize * @param componentId * @param result * @return */ private static Map<String, UserIssuesBO> createUserIssues(SonarClient sonarClient, Integer page, Integer pageSize, String componentId, Map<String, UserIssuesBO> result) { IssueQuery query = IssueQuery.create(); query.asc(true).pageSize(pageSize).pageIndex(page); query.urlParams().put("componentUuids", componentId); query.urlParams().put("facetMode", "count"); query.urlParams().put("facets", "rules,types,authors,resolutions"); query.urlParams().put("additionalFields", "_all"); IssueClient issueClient = sonarClient.issueClient(); System.out.print(""); Issues issues = issueClient.find(query); sum(result, issues); Paging paging = issues.paging(); Integer pages = paging.total() % pageSize > 0 ? ((paging.total() / pageSize) + 1) : (paging.total() % pageSize); //sonar 只支持查询 前10000行记录 if (page >= pages || page >= 20) { return result; } return createUserIssues(sonarClient, ++page, pageSize, componentId, result); } /** * @param result * @param issues */ private static void sum(Map<String, UserIssuesBO> result, Issues issues) { if (issues == null || com.suning.udmp.quark.CollectionUtils.isEmpty(issues.list())) { return; } for (Issue issue : issues.list()) { if (result.get(issue.author()) == null) { UserIssuesBO tmp = new UserIssuesBO(); tmp.setUserNo(issue.author()); result.put(issue.author(), tmp); } UserIssuesBO userIssuesBO = result.get(issue.author()); userIssuesBO.setProblem(userIssuesBO.getProblem() + 1); if (SeverityEnum.MAJOR.getCode().equals(issue.severity().toUpperCase())) { userIssuesBO.setMajorProblem(userIssuesBO.getMajorProblem() + 1); } else if (SeverityEnum.MINOR.getCode().equals(issue.severity().toUpperCase())) { userIssuesBO.setMinorProblem(userIssuesBO.getMinorProblem() + 1); } else if (SeverityEnum.CRITICAL.getCode().equals(issue.severity().toUpperCase())) { userIssuesBO.setSeriousProblem(userIssuesBO.getSeriousProblem() + 1); } else if (SeverityEnum.BLOCKER.getCode().equals(issue.severity().toUpperCase())) { userIssuesBO.setBlockProblem(userIssuesBO.getBlockProblem() + 1); } } } /** * @param componentId 全局视图 传 空 * @return */ public static RulesIssues getRulesIssues(String componentId) { // Sonar参数地址 String sonarHost = PropertiesReader.getProperty("jenkins.sonar.host"); //String sonarHost = "http://10.37.87.244:9000"; // 用户名 String sonarUsername = PropertiesReader.getProperty("sonar.userName"); // 密码 String sonarPwd = PropertiesReader.getProperty("sonar.passWd"); SonarRulesClient.Builder builder = SonarRulesClient.builder().url(sonarHost).login(sonarUsername).password(sonarPwd);//"http://sonar.cnsuning.com" SonarRulesClient sonarClient = builder.build(); return createRuleIssues(sonarClient, componentId);//"AV2cwEligP6n2VFNN5AE" } /** * @param sonarClient * @param componentId 全局视图 传 空 * @return */ private static RulesIssues createRuleIssues(SonarRulesClient sonarClient, String componentId) { IssueQuery query = IssueQuery.create(); query.pageSize(1).pageIndex(1); //非全局的视图数据 if (StringUtils.isNotBlank(componentId)) { query.urlParams().put("componentUuids", componentId); } query.urlParams().put("facets", "rules,authors,types"); query.urlParams().put("additionalFields", "_all"); RulesIssueClient issueClient = sonarClient.issueClient(); RulesIssues issues = (RulesIssues) issueClient.find(query); return issues; } private enum SeverityEnum { BLOCKER("BLOCKER"), CRITICAL("CRITICAL"), MAJOR("MAJOR"), MINOR("MINOR"),; private String code; private SeverityEnum(String code) { this.code = code; } public String getCode() { return code; } } public static class UserIssuesBO { private String userNo; private Integer problem = 0; private Integer majorProblem = 0; private Integer minorProblem = 0; private Integer seriousProblem = 0; private Integer blockProblem = 0; public String getUserNo() { return userNo; } public void setUserNo(String userNo) { this.userNo = userNo; } public Integer getProblem() { return problem; } public void setProblem(Integer problem) { this.problem = problem; } public Integer getMajorProblem() { return majorProblem; } public void setMajorProblem(Integer majorProblem) { this.majorProblem = majorProblem; } public Integer getMinorProblem() { return minorProblem; } public void setMinorProblem(Integer minorProblem) { this.minorProblem = minorProblem; } public Integer getSeriousProblem() { return seriousProblem; } public void setSeriousProblem(Integer seriousProblem) { this.seriousProblem = seriousProblem; } public Integer getBlockProblem() { return blockProblem; } public void setBlockProblem(Integer blockProblem) { this.blockProblem = blockProblem; } } }
对应的sonar-ws-client.jar相关类的源码:
org.sonar.wsclient.Sonar
package org.sonar.wsclient; import java.util.Collections; import java.util.List; import org.sonar.wsclient.connectors.Connector; import org.sonar.wsclient.connectors.ConnectorFactory; import org.sonar.wsclient.services.CreateQuery; import org.sonar.wsclient.services.DeleteQuery; import org.sonar.wsclient.services.Model; import org.sonar.wsclient.services.Query; import org.sonar.wsclient.services.UpdateQuery; import org.sonar.wsclient.services.WSUtils; import org.sonar.wsclient.unmarshallers.UnmarshalException; import org.sonar.wsclient.unmarshallers.Unmarshaller; import org.sonar.wsclient.unmarshallers.Unmarshallers; public class Sonar { private Connector connector; static { WSUtils.setInstance(new JdkUtils()); } public Sonar(Connector connector) { this.connector = connector; } public Connector getConnector() { return this.connector; } public <M extends Model> M find(Query<M> query) { String json = this.connector.execute(query); M result = null; if (json != null) { try { Unmarshaller<M> unmarshaller = Unmarshallers.forModel(query.getModelClass()); result = unmarshaller.toModel(json); } catch (Exception e) { throw new UnmarshalException(query, json, e); } } return result; } public <M extends Model> List<M> findAll(Query<M> query) { String json = this.connector.execute(query); List<M> result; List<M> result; if (json == null) { result = Collections.emptyList(); } else { try { Unmarshaller<M> unmarshaller = Unmarshallers.forModel(query.getModelClass()); result = unmarshaller.toModels(json); } catch (Exception e) { throw new UnmarshalException(query, json, e); } } return result; } public <M extends Model> M create(CreateQuery<M> query) { String json = this.connector.execute(query); M result = null; if (json != null) { try { Unmarshaller<M> unmarshaller = Unmarshallers.forModel(query.getModelClass()); result = unmarshaller.toModel(json); } catch (Exception e) { throw new UnmarshalException(query, json, e); } } return result; } public void update(UpdateQuery<?> query) { this.connector.execute(query); } public void delete(DeleteQuery query) { this.connector.execute(query); } public static Sonar create(String host) { return new Sonar(ConnectorFactory.create(new Host(host))); } public static Sonar create(String host, String username, String password) { return new Sonar(ConnectorFactory.create(new Host(host, username, password))); } }
org.sonar.wsclient.SonarClient
package org.sonar.wsclient; import javax.annotation.Nullable; import org.sonar.wsclient.internal.HttpRequestFactory; import org.sonar.wsclient.issue.ActionPlanClient; import org.sonar.wsclient.issue.IssueClient; import org.sonar.wsclient.issue.internal.DefaultActionPlanClient; import org.sonar.wsclient.issue.internal.DefaultIssueClient; import org.sonar.wsclient.permissions.PermissionClient; import org.sonar.wsclient.permissions.internal.DefaultPermissionClient; import org.sonar.wsclient.project.ProjectClient; import org.sonar.wsclient.project.internal.DefaultProjectClient; import org.sonar.wsclient.qualitygate.QualityGateClient; import org.sonar.wsclient.qualitygate.internal.DefaultQualityGateClient; import org.sonar.wsclient.rule.RuleClient; import org.sonar.wsclient.rule.RuleTagClient; import org.sonar.wsclient.rule.internal.DefaultRuleClient; import org.sonar.wsclient.rule.internal.DefaultRuleTagClient; import org.sonar.wsclient.system.SystemClient; import org.sonar.wsclient.system.internal.DefaultSystemClient; import org.sonar.wsclient.user.UserClient; import org.sonar.wsclient.user.internal.DefaultUserClient; public class SonarClient { public static final int DEFAULT_CONNECT_TIMEOUT_MILLISECONDS = 30000; public static final int DEFAULT_READ_TIMEOUT_MILLISECONDS = 60000; final HttpRequestFactory requestFactory; private SonarClient(Builder builder) { this.requestFactory = new HttpRequestFactory(builder.url).setLogin(builder.login).setPassword(builder.password).setProxyHost(builder.proxyHost).setProxyPort(builder.proxyPort).setProxyLogin(builder.proxyLogin).setProxyPassword(builder.proxyPassword).setConnectTimeoutInMilliseconds(builder.connectTimeoutMs).setReadTimeoutInMilliseconds(builder.readTimeoutMs); } public IssueClient issueClient() { return new DefaultIssueClient(this.requestFactory); } public ActionPlanClient actionPlanClient() { return new DefaultActionPlanClient(this.requestFactory); } public UserClient userClient() { return new DefaultUserClient(this.requestFactory); } public PermissionClient permissionClient() { return new DefaultPermissionClient(this.requestFactory); } public ProjectClient projectClient() { return new DefaultProjectClient(this.requestFactory); } public RuleTagClient ruleTagClient() { return new DefaultRuleTagClient(this.requestFactory); } public RuleClient ruleClient() { return new DefaultRuleClient(this.requestFactory); } public QualityGateClient qualityGateClient() { return new DefaultQualityGateClient(this.requestFactory); } public SystemClient systemClient() { return new DefaultSystemClient(this.requestFactory); } public static Builder builder() { return new Builder(null); } public static SonarClient create(String serverUrl) { return builder().url(serverUrl).build(); } public static class Builder { private String login; private String password; private String url; private String proxyHost; private String proxyLogin; private String proxyPassword; private int proxyPort = 0; private int connectTimeoutMs = 30000; private int readTimeoutMs = 60000; public Builder url(String url) { this.url = url; return this; } public Builder login(@Nullable String login) { this.login = login; return this; } public Builder password(@Nullable String password) { this.password = password; return this; } public Builder proxy(@Nullable String proxyHost, int proxyPort) { this.proxyHost = proxyHost; this.proxyPort = proxyPort; return this; } public Builder proxyLogin(@Nullable String proxyLogin) { this.proxyLogin = proxyLogin; return this; } public Builder proxyPassword(@Nullable String proxyPassword) { this.proxyPassword = proxyPassword; return this; } public Builder connectTimeoutMilliseconds(int i) { this.connectTimeoutMs = i; return this; } public Builder readTimeoutMilliseconds(int i) { this.readTimeoutMs = i; return this; } public SonarClient build() { if ((this.url == null) || ("".equals(this.url))) { throw new IllegalStateException("Server URL must be set"); } return new SonarClient(this, null); } } }
org.sonar.wsclient.services.ResourceQuery
package org.sonar.wsclient.services; public class ResourceQuery extends Query<Resource> { public static final String BASE_URL = "/api/resources"; public static final int DEPTH_UNLIMITED = -1; private Integer depth; private String resourceKeyOrId; private Integer limit; private String[] scopes; private String[] qualifiers; private String[] metrics; private String[] rules; private String[] ruleSeverities; private String[] characteristicKeys; private boolean excludeRules = true; private boolean excludeRuleSeverities = true; private Boolean includeTrends = null; private Boolean includeAlerts = null; private Boolean verbose = Boolean.FALSE; public ResourceQuery() {} public ResourceQuery(String resourceKeyOrId) { this.resourceKeyOrId = resourceKeyOrId; } public ResourceQuery(long resourceId) { this.resourceKeyOrId = String.valueOf(resourceId); } public Integer getDepth() { return this.depth; } public ResourceQuery setDepth(Integer depth) { this.depth = depth; return this; } public ResourceQuery setAllDepths() { return setDepth(Integer.valueOf(-1)); } public String getResourceKeyOrId() { return this.resourceKeyOrId; } public ResourceQuery setResourceKeyOrId(String resourceKeyOrId) { this.resourceKeyOrId = resourceKeyOrId; return this; } public ResourceQuery setResourceId(int resourceId) { this.resourceKeyOrId = Integer.toString(resourceId); return this; } public ResourceQuery setCharacteristics(String... keys) { this.characteristicKeys = keys; return this; } public Integer getLimit() { return this.limit; } public ResourceQuery setLimit(Integer limit) { this.limit = limit; return this; } public String[] getScopes() { return this.scopes; } public ResourceQuery setScopes(String... scopes) { this.scopes = scopes; return this; } public String[] getQualifiers() { return this.qualifiers; } public ResourceQuery setQualifiers(String... qualifiers) { this.qualifiers = qualifiers; return this; } public String[] getMetrics() { return this.metrics; } public ResourceQuery setMetrics(String... metrics) { this.metrics = metrics; return this; } public String[] getRules() { return this.rules; } public ResourceQuery setRules(String... rules) { this.rules = rules; this.excludeRules = false; return this; } @Deprecated public String[] getRuleCategories() { return null; } @Deprecated public ResourceQuery setRuleCategories(String... ruleCategories) { return this; } public String[] getRuleSeverities() { return this.ruleSeverities; } public ResourceQuery setRuleSeverities(String... ruleSeverities) { this.ruleSeverities = ruleSeverities; this.excludeRuleSeverities = false; return this; } @Deprecated public String[] getRulePriorities() { return this.ruleSeverities; } @Deprecated public ResourceQuery setRulePriorities(String... rulePriorities) { return setRuleSeverities(rulePriorities); } public boolean isExcludeRules() { return this.excludeRules; } public ResourceQuery setExcludeRules(boolean excludeRules) { this.excludeRules = excludeRules; return this; } @Deprecated public boolean isExcludeRuleCategories() { return false; } @Deprecated public ResourceQuery setExcludeRuleCategories(boolean b) { return this; } public boolean isExcludeRuleSeverities() { return this.excludeRuleSeverities; } public ResourceQuery setExcludeRuleSeverities(boolean excludeRuleSeverities) { this.excludeRuleSeverities = excludeRuleSeverities; return this; } @Deprecated public boolean isExcludeRulePriorities() { return this.excludeRuleSeverities; } @Deprecated public ResourceQuery setExcludeRulePriorities(boolean b) { this.excludeRuleSeverities = b; return this; } public Boolean isVerbose() { return this.verbose; } public ResourceQuery setVerbose(Boolean verbose) { this.verbose = verbose; return this; } public Boolean isIncludeTrends() { return this.includeTrends; } public ResourceQuery setIncludeTrends(Boolean includeTrends) { this.includeTrends = includeTrends; return this; } public Boolean isIncludeAlerts() { return this.includeAlerts; } public ResourceQuery setIncludeAlerts(Boolean includeAlerts) { this.includeAlerts = includeAlerts; return this; } public String getUrl() { StringBuilder url = new StringBuilder("/api/resources"); url.append('?'); appendUrlParameter(url, "resource", this.resourceKeyOrId); appendUrlParameter(url, "metrics", this.metrics); appendUrlParameter(url, "scopes", this.scopes); appendUrlParameter(url, "qualifiers", this.qualifiers); appendUrlParameter(url, "depth", this.depth); appendUrlParameter(url, "limit", this.limit); appendRuleField(url, "rules", this.excludeRules, this.rules); appendRuleField(url, "rule_priorities", this.excludeRuleSeverities, this.ruleSeverities); appendUrlParameter(url, "includetrends", this.includeTrends); appendUrlParameter(url, "characteristics", this.characteristicKeys); appendUrlParameter(url, "includealerts", this.includeAlerts); appendUrlParameter(url, "verbose", this.verbose); return url.toString(); } private void appendRuleField(StringBuilder url, String field, boolean excludeField, String[] list) { if (!excludeField) { if ((list == null) || (list.length == 0)) { appendUrlParameter(url, field, Boolean.valueOf(true)); } else { appendUrlParameter(url, field, list); } } } public final Class<Resource> getModelClass() { return Resource.class; } public static ResourceQuery createForMetrics(String resourceKeyOrId, String... metricKeys) { return new ResourceQuery(resourceKeyOrId).setMetrics(metricKeys); } public static ResourceQuery createForResource(Resource resource, String... metricKeys) { Integer id = resource.getId(); if (id == null) { throw new IllegalArgumentException("id must be set"); } return new ResourceQuery(id.toString()).setMetrics(metricKeys); } public static ResourceQuery create(String resourceKey) { return new ResourceQuery(resourceKey); } }
public abstract class Query<M extends Model> extends AbstractQuery<M> { public abstract Class<M> getModelClass(); }
package org.sonar.wsclient.services; import java.util.Date; import javax.annotation.Nullable; public abstract class AbstractQuery<M extends Model> { public static final int DEFAULT_TIMEOUT_MILLISECONDS = 30000; private int timeoutMilliseconds = 30000; private String locale; public abstract String getUrl(); public String getBody() { return null; } public final int getTimeoutMilliseconds() { return this.timeoutMilliseconds; } public final AbstractQuery<M> setTimeoutMilliseconds(int i) { this.timeoutMilliseconds = (i < 0 ? 0 : i); return this; } public final String getLocale() { return this.locale; } public final AbstractQuery<M> setLocale(String locale) { this.locale = locale; return this; } protected static String encode(String value) { return WSUtils.getINSTANCE().encodeUrl(value); } protected static void appendUrlParameter(StringBuilder url, String paramKey, int paramValue) { url.append(paramKey).append('=').append(paramValue).append("&"); } protected static void appendUrlParameter(StringBuilder url, String paramKey, @Nullable Object paramValue) { if (paramValue != null) { url.append(paramKey).append('=').append(encode(paramValue.toString())).append('&'); } } protected static void appendUrlParameter(StringBuilder url, String paramKey, @Nullable Object[] paramValues) { if (paramValues != null) { url.append(paramKey).append('='); for (int index = 0; index < paramValues.length; index++) { if (index > 0) { url.append(','); } if (paramValues[index] != null) { url.append(encode(paramValues[index].toString())); } } url.append('&'); } } protected static void appendUrlParameter(StringBuilder url, String paramKey, @Nullable Date paramValue, boolean includeTime) { if (paramValue != null) { String format = includeTime ? "yyyy-MM-dd'T'HH:mm:ssZ" : "yyyy-MM-dd"; url.append(paramKey).append('=').append(encode(WSUtils.getINSTANCE().format(paramValue, format))).append('&'); } } }