mirror of
https://github.com/github/codeql.git
synced 2026-05-16 20:27:06 +02:00
Compare commits
4 Commits
codeql-cli
...
sauyon/jav
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
133ce0096b | ||
|
|
07959b5a90 | ||
|
|
3486ce2be5 | ||
|
|
a2c84023d6 |
2
java/change-notes/2021-03-25-add-spring-stringutils.md
Normal file
2
java/change-notes/2021-03-25-add-spring-stringutils.md
Normal file
@@ -0,0 +1,2 @@
|
||||
lgtm,codescanning
|
||||
* Added additional taint steps modeling the Spring StringUtils class (`org.springframework.util.StringUtils`).
|
||||
@@ -32,6 +32,7 @@ import semmle.code.java.frameworks.spring.SpringQualifier
|
||||
import semmle.code.java.frameworks.spring.SpringRef
|
||||
import semmle.code.java.frameworks.spring.SpringReplacedMethod
|
||||
import semmle.code.java.frameworks.spring.SpringSet
|
||||
import semmle.code.java.frameworks.spring.SpringStringUtils
|
||||
import semmle.code.java.frameworks.spring.SpringValue
|
||||
import semmle.code.java.frameworks.spring.SpringXMLElement
|
||||
import semmle.code.java.frameworks.spring.metrics.MetricSpringBean
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/** Definitions of flow steps through utility methods of `org.springframework.util.SpringUtils`. */
|
||||
|
||||
import java
|
||||
private import semmle.code.java.dataflow.ExternalFlow
|
||||
|
||||
private class SpringStringUtilsModel extends SummaryModelCsv {
|
||||
override predicate row(string row) {
|
||||
row =
|
||||
[
|
||||
"org.springframework.util;StringUtils;false;addStringToArray;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;applyRelativePath;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;arrayToCommaDelimitedString;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;arrayToDelimitedString;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;capitalize;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;cleanPath;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;collectionToCommaDelimitedString;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;collectionToDelimitedString;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;collectionToDelimitedString;(java.util.Collection,java.lang.String,java.lang.String,java.lang.String);;Argument[2..3];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;commaDelimitedListToSet;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;commaDelimitedListToStringArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;concatenateStringArrays;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;delete;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;deleteAny;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;delimitedListToStringArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;getFilename;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;getFilenameExtension;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;mergeStringArrays;;;Argument[0..1];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;quote;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;quoteIfString;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;removeDuplicateStrings;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;replace;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;replace;;;Argument[2];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;sortStringArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;split;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;splitArrayElementsIntoProperties;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;stripFilenameExtension;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;tokenizeToStringArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;toStringArray;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;trimAllWhitespace;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;trimArrayElements;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;trimLeadingCharacter;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;trimLeadingWhitespace;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;trimTrailingCharacter;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;trimTrailingWhitespace;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;trimWhitespace;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;uncapitalize;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;unqualify;;;Argument[0];ReturnValue;taint",
|
||||
"org.springframework.util;StringUtils;false;uriDecode;;;Argument[0];ReturnValue;taint"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,125 @@
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
import java.lang.String;
|
||||
|
||||
class StringUtilsTest {
|
||||
String taint() { return "tainted"; }
|
||||
|
||||
String[] taintArray() { return null; }
|
||||
|
||||
Locale taintLocale() { return null; }
|
||||
|
||||
Collection<String> taintedCollection() { return null; }
|
||||
|
||||
Enumeration<String> taintedEnumeration() { return null; }
|
||||
|
||||
void sink(Object o) {}
|
||||
|
||||
void test() throws Exception {
|
||||
sink(StringUtils.addStringToArray(null, taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.addStringToArray(taintArray(), "")); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.applyRelativePath("/", taint())); // $hasTaintFlow
|
||||
sink(StringUtils.applyRelativePath(taint(), "../../test")); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.arrayToCommaDelimitedString(taintArray())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.arrayToDelimitedString(taintArray(), ":")); // $hasTaintFlow
|
||||
sink(StringUtils.arrayToDelimitedString(null, taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.capitalize(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.cleanPath(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.collectionToCommaDelimitedString(taintedCollection())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.collectionToDelimitedString(taintedCollection(), ":")); // $hasTaintFlow
|
||||
sink(StringUtils.collectionToDelimitedString(null, taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.collectionToDelimitedString(taintedCollection(), ":", "", "")); // $hasTaintFlow
|
||||
sink(StringUtils.collectionToDelimitedString(null, taint(), "", "")); // $hasTaintFlow
|
||||
sink(StringUtils.collectionToDelimitedString(null, ":", taint(), "")); // $hasTaintFlow
|
||||
sink(StringUtils.collectionToDelimitedString(null, ":", "", taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.commaDelimitedListToSet(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.commaDelimitedListToStringArray(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.concatenateStringArrays(taintArray(), null)); // $hasTaintFlow
|
||||
sink(StringUtils.concatenateStringArrays(null, taintArray())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.delete(taint(), "")); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.deleteAny(taint(), "")); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.delimitedListToStringArray(taint(), ":")); // $hasTaintFlow
|
||||
sink(StringUtils.delimitedListToStringArray(taint(), ":", ".")); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.getFilename(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.getFilenameExtension(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.mergeStringArrays(taintArray(), null)); // $hasTaintFlow
|
||||
sink(StringUtils.mergeStringArrays(null, taintArray())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.parseLocale(taint()));
|
||||
|
||||
sink(StringUtils.parseLocaleString(taint()));
|
||||
|
||||
sink(StringUtils.parseTimeZoneString(taint()));
|
||||
|
||||
sink(StringUtils.quote(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.quoteIfString(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.removeDuplicateStrings(taintArray())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.replace(taint(), "", "")); // $hasTaintFlow
|
||||
sink(StringUtils.replace("", "", taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.sortStringArray(taintArray())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.split(taint(), "")); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.splitArrayElementsIntoProperties(taintArray(), "")); // $hasTaintFlow
|
||||
sink(StringUtils.splitArrayElementsIntoProperties(taintArray(), "", "")); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.stripFilenameExtension(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.tokenizeToStringArray(taint(), "")); // $hasTaintFlow
|
||||
sink(StringUtils.tokenizeToStringArray(taint(), "", true, true)); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.toLanguageTag(taintLocale()));
|
||||
|
||||
sink(StringUtils.toStringArray(taintedCollection())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.toStringArray(taintedEnumeration())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.trimAllWhitespace(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.trimArrayElements(taintArray())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.trimLeadingCharacter(taint(), 'a')); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.trimLeadingWhitespace(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.trimTrailingCharacter(taint(), 'a')); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.trimTrailingWhitespace(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.trimWhitespace(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.uncapitalize(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.unqualify(taint())); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.unqualify(taint(), '.')); // $hasTaintFlow
|
||||
|
||||
sink(StringUtils.uriDecode(taint(), java.nio.charset.StandardCharsets.UTF_8)); // $hasTaintFlow
|
||||
}
|
||||
}
|
||||
53
java/ql/test/library-tests/frameworks/spring/flow.ql
Normal file
53
java/ql/test/library-tests/frameworks/spring/flow.ql
Normal file
@@ -0,0 +1,53 @@
|
||||
import java
|
||||
import semmle.code.java.frameworks.spring.Spring
|
||||
import semmle.code.java.dataflow.TaintTracking
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class TaintFlowConf extends TaintTracking::Configuration {
|
||||
TaintFlowConf() { this = "qltest:frameworks:spring-taint-flow" }
|
||||
|
||||
override predicate isSource(DataFlow::Node n) {
|
||||
exists(string name | name.matches("taint%") |
|
||||
n.asExpr().(MethodAccess).getMethod().hasName(name)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node n) {
|
||||
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
|
||||
}
|
||||
}
|
||||
|
||||
class ValueFlowConf extends DataFlow::Configuration {
|
||||
ValueFlowConf() { this = "qltest:frameworks:spring-value-flow" }
|
||||
|
||||
override predicate isSource(DataFlow::Node n) {
|
||||
n.asExpr().(MethodAccess).getMethod().hasName("taint")
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node n) {
|
||||
exists(MethodAccess ma | ma.getMethod().hasName("sink") | n.asExpr() = ma.getAnArgument())
|
||||
}
|
||||
}
|
||||
|
||||
class HasFlowTest extends InlineExpectationsTest {
|
||||
HasFlowTest() { this = "HasFlowTest" }
|
||||
|
||||
override string getARelevantTag() { result = ["hasTaintFlow", "hasValueFlow"] }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
tag = "hasTaintFlow" and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink, TaintFlowConf conf | conf.hasFlow(src, sink) |
|
||||
not any(ValueFlowConf vconf).hasFlow(src, sink) and
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
)
|
||||
or
|
||||
tag = "hasValueFlow" and
|
||||
exists(DataFlow::Node src, DataFlow::Node sink, ValueFlowConf conf | conf.hasFlow(src, sink) |
|
||||
sink.getLocation() = location and
|
||||
element = sink.toString() and
|
||||
value = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
1
java/ql/test/library-tests/frameworks/spring/options
Normal file
1
java/ql/test/library-tests/frameworks/spring/options
Normal file
@@ -0,0 +1 @@
|
||||
//semmle-extractor-options: --javac-args -cp ${testdir}/../../../stubs/springframework-5.2.3
|
||||
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* https://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.springframework.util;
|
||||
|
||||
import java.nio.charset.Charset;
|
||||
import java.util.Collection;
|
||||
import java.util.Enumeration;
|
||||
import java.util.Locale;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.TimeZone;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
public abstract class StringUtils {
|
||||
public static boolean isEmpty(@Nullable Object str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasLength(@Nullable CharSequence str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasLength(@Nullable String str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasText(@Nullable CharSequence str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean hasText(@Nullable String str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean containsWhitespace(@Nullable CharSequence str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean containsWhitespace(@Nullable String str) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String trimWhitespace(String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String trimAllWhitespace(String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String trimLeadingWhitespace(String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String trimTrailingWhitespace(String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String trimLeadingCharacter(String str, char leadingCharacter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String trimTrailingCharacter(String str, char trailingCharacter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean startsWithIgnoreCase(@Nullable String str, @Nullable String prefix) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean endsWithIgnoreCase(@Nullable String str, @Nullable String suffix) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static boolean substringMatch(CharSequence str, int index, CharSequence substring) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static int countOccurrencesOf(String str, String sub) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public static String replace(String inString, String oldPattern, @Nullable String newPattern) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String delete(String inString, String pattern) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String deleteAny(String inString, @Nullable String charsToDelete) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String quote(@Nullable String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Object quoteIfString(@Nullable Object obj) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String unqualify(String qualifiedName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String unqualify(String qualifiedName, char separator) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String capitalize(String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String uncapitalize(String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getFilename(@Nullable String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getFilenameExtension(@Nullable String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String stripFilenameExtension(String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String applyRelativePath(String path, String relativePath) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String cleanPath(String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static boolean pathEquals(String path1, String path2) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public static String uriDecode(String source, Charset charset) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Locale parseLocale(String localeValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Locale parseLocaleString(String localeString) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String toLanguageTag(Locale locale) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static TimeZone parseTimeZoneString(String timeZoneString) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] toStringArray(@Nullable Collection<String> collection) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] toStringArray(@Nullable Enumeration<String> enumeration) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] addStringToArray(@Nullable String[] array, String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] concatenateStringArrays(
|
||||
@Nullable String[] array1, @Nullable String[] array2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] mergeStringArrays(@Nullable String[] array1, @Nullable String[] array2) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] sortStringArray(String[] array) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] trimArrayElements(String[] array) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] removeDuplicateStrings(String[] array) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] split(@Nullable String toSplit, @Nullable String delimiter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Properties splitArrayElementsIntoProperties(String[] array, String delimiter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Properties splitArrayElementsIntoProperties(
|
||||
String[] array, String delimiter, @Nullable String charsToDelete) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] tokenizeToStringArray(@Nullable String str, String delimiters) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] tokenizeToStringArray(
|
||||
@Nullable String str, String delimiters, boolean trimTokens, boolean ignoreEmptyTokens) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] delimitedListToStringArray(
|
||||
@Nullable String str, @Nullable String delimiter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] delimitedListToStringArray(
|
||||
@Nullable String str, @Nullable String delimiter, @Nullable String charsToDelete) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String[] commaDelimitedListToStringArray(@Nullable String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Set<String> commaDelimitedListToSet(@Nullable String str) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String collectionToDelimitedString(
|
||||
@Nullable Collection<?> coll, String delim, String prefix, String suffix) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String collectionToDelimitedString(@Nullable Collection<?> coll, String delim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String collectionToCommaDelimitedString(@Nullable Collection<?> coll) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String arrayToDelimitedString(@Nullable Object[] arr, String delim) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String arrayToCommaDelimitedString(@Nullable Object[] arr) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user