diff --git a/Java/commons-lang-CharEncoding_93/Dockerfile b/Java/commons-lang-CharEncoding_93/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharEncoding_93/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharEncoding_93/buggy.java b/Java/commons-lang-CharEncoding_93/buggy.java new file mode 100644 index 000000000..025026346 --- /dev/null +++ b/Java/commons-lang-CharEncoding_93/buggy.java @@ -0,0 +1,114 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +import java.nio.charset.Charset; +import java.nio.charset.IllegalCharsetNameException; + +/** + *

Character encoding names required of every implementation of the Java platform.

+ * + *

According to JRE character + * encoding names:

+ * + *

Every implementation of the Java platform is required to support the following character encodings. + * Consult the release documentation for your implementation to see if any other encodings are supported. + *

+ * + * @see JRE character encoding names + * @since 2.1 + */ +public class CharEncoding { + + /** + *

ISO Latin Alphabet #1, also known as ISO-LATIN-1.

+ * + *

Every implementation of the Java platform is required to support this character encoding.

+ */ + public static final String ISO_8859_1 = "ISO-8859-1"; + + /** + *

Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block + * of the Unicode character set.

+ * + *

Every implementation of the Java platform is required to support this character encoding.

+ */ + public static final String US_ASCII = "US-ASCII"; + + /** + *

Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial + * byte-order mark (either order accepted on input, big-endian used on output).

+ * + *

Every implementation of the Java platform is required to support this character encoding.

+ */ + public static final String UTF_16 = "UTF-16"; + + /** + *

Sixteen-bit Unicode Transformation Format, big-endian byte order.

+ * + *

Every implementation of the Java platform is required to support this character encoding.

+ */ + public static final String UTF_16BE = "UTF-16BE"; + + /** + *

Sixteen-bit Unicode Transformation Format, little-endian byte order.

+ * + *

Every implementation of the Java platform is required to support this character encoding.

+ */ + public static final String UTF_16LE = "UTF-16LE"; + + /** + *

Eight-bit Unicode Transformation Format.

+ * + *

Every implementation of the Java platform is required to support this character encoding.

+ */ + public static final String UTF_8 = "UTF-8"; + + /** + *

Returns whether the named charset is supported.

+ * + *

This is similar to + * java.nio.charset.Charset.isSupported(String) but handles more formats

+ * + * @param name the name of the requested charset; may be either a canonical name or an alias, null returns false + * @return {@code true} if the charset is available in the current Java virtual machine + */ +/** + *

Returns whether the named charset is supported.

+ * + *

This is similar to + * java.nio.charset.Charset.isSupported(String) but handles more formats

+ * + * @param name + * the name of the requested charset; may be either a canonical name or an alias, null returns false + * @return {@code true} if the charset is available in the current Java virtual machine + */ +public static boolean isSupported(final java.lang.String name) { + { + try { + return java.nio.charset.Charset.isSupported(/* NPEX_NULL_EXP */ + name); + } catch (final java.nio.charset.IllegalCharsetNameException ex) { + return false; + } + } +} + +} diff --git a/Java/commons-lang-CharEncoding_93/metadata.json b/Java/commons-lang-CharEncoding_93/metadata.json new file mode 100644 index 000000000..1d5286878 --- /dev/null +++ b/Java/commons-lang-CharEncoding_93/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharEncoding_93", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/CharEncoding.java", + "line": 107, + "npe_method": "isSupported", + "deref_field": "name", + "npe_class": "CharEncoding", + "repo": "commons-lang", + "bug_id": "CharEncoding_93" + } +} diff --git a/Java/commons-lang-CharEncoding_93/npe.json b/Java/commons-lang-CharEncoding_93/npe.json new file mode 100644 index 000000000..8a64b13b6 --- /dev/null +++ b/Java/commons-lang-CharEncoding_93/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/CharEncoding.java", + "line": 107, + "npe_method": "isSupported", + "deref_field": "name", + "npe_class": "CharEncoding" +} \ No newline at end of file diff --git a/Java/commons-lang-CharSequenceTranslator_55/Dockerfile b/Java/commons-lang-CharSequenceTranslator_55/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_55/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharSequenceTranslator_55/buggy.java b/Java/commons-lang-CharSequenceTranslator_55/buggy.java new file mode 100644 index 000000000..bd887b3e6 --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_55/buggy.java @@ -0,0 +1,142 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.text.translate; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Locale; + +/** + * An API for translating text. + * Its core use is to escape and unescape text. Because escaping and unescaping + * is completely contextual, the API does not present two separate signatures. + * + * @since 3.0 + */ +public abstract class CharSequenceTranslator { + + static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + + /** + * Translate a set of codepoints, represented by an int index into a CharSequence, + * into another set of codepoints. The number of codepoints consumed must be returned, + * and the only IOExceptions thrown must be from interacting with the Writer so that + * the top level API may reliably ignore StringWriter IOExceptions. + * + * @param input CharSequence that is being translated + * @param index int representing the current point of translation + * @param out Writer to translate the text to + * @return int count of codepoints consumed + * @throws IOException if and only if the Writer produces an IOException + */ + public abstract int translate(CharSequence input, int index, Writer out) throws IOException; + + /** + * Helper for non-Writer usage. + * @param input CharSequence to be translated + * @return String output of translation + */ +/** + * Helper for non-Writer usage. + * + * @param input + * CharSequence to be translated + * @return String output of translation + */ +public final java.lang.String translate(final java.lang.CharSequence input) { + { + try { + final java.io.StringWriter writer = new java.io.StringWriter(/* NPEX_NULL_EXP */ + input.length() * 2); + translate(input, writer); + return writer.toString(); + } catch (final java.io.IOException ioe) { + // this should never ever happen while writing to a StringWriter + throw new java.lang.RuntimeException(ioe); + } + } +} + + /** + * Translate an input onto a Writer. This is intentionally final as its algorithm is + * tightly coupled with the abstract method of this class. + * + * @param input CharSequence that is being translated + * @param out Writer to translate the text to + * @throws IOException if and only if the Writer produces an IOException + */ + public final void translate(final CharSequence input, final Writer out) throws IOException { + if (out == null) { + throw new IllegalArgumentException("The Writer must not be null"); + } + if (input == null) { + return; + } + int pos = 0; + final int len = input.length(); + while (pos < len) { + final int consumed = translate(input, pos, out); + if (consumed == 0) { + // inlined implementation of Character.toChars(Character.codePointAt(input, pos)) + // avoids allocating temp char arrays and duplicate checks + char c1 = input.charAt(pos); + out.write(c1); + pos++; + if (Character.isHighSurrogate(c1) && pos < len) { + char c2 = input.charAt(pos); + if (Character.isLowSurrogate(c2)) { + out.write(c2); + pos++; + } + } + continue; + } + // contract with translators is that they have to understand codepoints + // and they just took care of a surrogate pair + for (int pt = 0; pt < consumed; pt++) { + pos += Character.charCount(Character.codePointAt(input, pos)); + } + } + } + + /** + * Helper method to create a merger of this translator with another set of + * translators. Useful in customizing the standard functionality. + * + * @param translators CharSequenceTranslator array of translators to merge with this one + * @return CharSequenceTranslator merging this translator with the others + */ + public final CharSequenceTranslator with(final CharSequenceTranslator... translators) { + final CharSequenceTranslator[] newArray = new CharSequenceTranslator[translators.length + 1]; + newArray[0] = this; + System.arraycopy(translators, 0, newArray, 1, translators.length); + return new AggregateTranslator(newArray); + } + + /** + *

Returns an upper case hexadecimal String for the given + * character.

+ * + * @param codepoint The codepoint to convert. + * @return An upper case hexadecimal String + */ + public static String hex(final int codepoint) { + return Integer.toHexString(codepoint).toUpperCase(Locale.ENGLISH); + } + +} diff --git a/Java/commons-lang-CharSequenceTranslator_55/metadata.json b/Java/commons-lang-CharSequenceTranslator_55/metadata.json new file mode 100644 index 000000000..c99c31a05 --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_55/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharSequenceTranslator_55", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java", + "line": 65, + "npe_method": "translate", + "deref_field": "input", + "npe_class": "CharSequenceTranslator", + "repo": "commons-lang", + "bug_id": "CharSequenceTranslator_55" + } +} diff --git a/Java/commons-lang-CharSequenceTranslator_55/npe.json b/Java/commons-lang-CharSequenceTranslator_55/npe.json new file mode 100644 index 000000000..5a1d7f2b4 --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_55/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java", + "line": 65, + "npe_method": "translate", + "deref_field": "input", + "npe_class": "CharSequenceTranslator" +} \ No newline at end of file diff --git a/Java/commons-lang-CharSequenceTranslator_77/Dockerfile b/Java/commons-lang-CharSequenceTranslator_77/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_77/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharSequenceTranslator_77/buggy.java b/Java/commons-lang-CharSequenceTranslator_77/buggy.java new file mode 100644 index 000000000..ae1a9d4ca --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_77/buggy.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.text.translate; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Locale; + +/** + * An API for translating text. + * Its core use is to escape and unescape text. Because escaping and unescaping + * is completely contextual, the API does not present two separate signatures. + * + * @since 3.0 + */ +public abstract class CharSequenceTranslator { + + static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + + /** + * Translate a set of codepoints, represented by an int index into a CharSequence, + * into another set of codepoints. The number of codepoints consumed must be returned, + * and the only IOExceptions thrown must be from interacting with the Writer so that + * the top level API may reliably ignore StringWriter IOExceptions. + * + * @param input CharSequence that is being translated + * @param index int representing the current point of translation + * @param out Writer to translate the text to + * @return int count of codepoints consumed + * @throws IOException if and only if the Writer produces an IOException + */ + public abstract int translate(CharSequence input, int index, Writer out) throws IOException; + + /** + * Helper for non-Writer usage. + * @param input CharSequence to be translated + * @return String output of translation + */ + public final String translate(final CharSequence input) { + if (input == null) { + return null; + } + try { + final StringWriter writer = new StringWriter(input.length() * 2); + translate(input, writer); + return writer.toString(); + } catch (final IOException ioe) { + // this should never ever happen while writing to a StringWriter + throw new RuntimeException(ioe); + } + } + + /** + * Translate an input onto a Writer. This is intentionally final as its algorithm is + * tightly coupled with the abstract method of this class. + * + * @param input CharSequence that is being translated + * @param out Writer to translate the text to + * @throws IOException if and only if the Writer produces an IOException + */ +/** + * Translate an input onto a Writer. This is intentionally final as its algorithm is + * tightly coupled with the abstract method of this class. + * + * @param input + * CharSequence that is being translated + * @param out + * Writer to translate the text to + * @throws IOException + * if and only if the Writer produces an IOException + */ +public final void translate(final java.lang.CharSequence input, final java.io.Writer out) throws java.io.IOException { + { + if (input == null) { + return; + } + int pos = 0; + final int len = input.length(); + while (pos < len) { + final int consumed = translate(input, pos, /* NPEX_NULL_EXP */ + out); + if (consumed == 0) { + // inlined implementation of Character.toChars(Character.codePointAt(input, pos)) + // avoids allocating temp char arrays and duplicate checks + char c1 = input.charAt(pos); + out.write(c1); + pos++; + if (java.lang.Character.isHighSurrogate(c1) && (pos < len)) { + char c2 = input.charAt(pos); + if (java.lang.Character.isLowSurrogate(c2)) { + out.write(c2); + pos++; + } + } + continue; + } + // contract with translators is that they have to understand codepoints + // and they just took care of a surrogate pair + for (int pt = 0; pt < consumed; pt++) { + pos += java.lang.Character.charCount(java.lang.Character.codePointAt(input, pos)); + } + } + } +} + + /** + * Helper method to create a merger of this translator with another set of + * translators. Useful in customizing the standard functionality. + * + * @param translators CharSequenceTranslator array of translators to merge with this one + * @return CharSequenceTranslator merging this translator with the others + */ + public final CharSequenceTranslator with(final CharSequenceTranslator... translators) { + final CharSequenceTranslator[] newArray = new CharSequenceTranslator[translators.length + 1]; + newArray[0] = this; + System.arraycopy(translators, 0, newArray, 1, translators.length); + return new AggregateTranslator(newArray); + } + + /** + *

Returns an upper case hexadecimal String for the given + * character.

+ * + * @param codepoint The codepoint to convert. + * @return An upper case hexadecimal String + */ + public static String hex(final int codepoint) { + return Integer.toHexString(codepoint).toUpperCase(Locale.ENGLISH); + } + +} diff --git a/Java/commons-lang-CharSequenceTranslator_77/metadata.json b/Java/commons-lang-CharSequenceTranslator_77/metadata.json new file mode 100644 index 000000000..7bbcf1c4e --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_77/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharSequenceTranslator_77", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java", + "line": 96, + "npe_method": "translate", + "deref_field": "out", + "npe_class": "CharSequenceTranslator", + "repo": "commons-lang", + "bug_id": "CharSequenceTranslator_77" + } +} diff --git a/Java/commons-lang-CharSequenceTranslator_77/npe.json b/Java/commons-lang-CharSequenceTranslator_77/npe.json new file mode 100644 index 000000000..dae78ac5e --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_77/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java", + "line": 96, + "npe_method": "translate", + "deref_field": "out", + "npe_class": "CharSequenceTranslator" +} \ No newline at end of file diff --git a/Java/commons-lang-CharSequenceTranslator_80/Dockerfile b/Java/commons-lang-CharSequenceTranslator_80/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_80/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharSequenceTranslator_80/buggy.java b/Java/commons-lang-CharSequenceTranslator_80/buggy.java new file mode 100644 index 000000000..d9daf52fa --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_80/buggy.java @@ -0,0 +1,146 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.text.translate; + +import java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.Locale; + +/** + * An API for translating text. + * Its core use is to escape and unescape text. Because escaping and unescaping + * is completely contextual, the API does not present two separate signatures. + * + * @since 3.0 + */ +public abstract class CharSequenceTranslator { + + static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'}; + + /** + * Translate a set of codepoints, represented by an int index into a CharSequence, + * into another set of codepoints. The number of codepoints consumed must be returned, + * and the only IOExceptions thrown must be from interacting with the Writer so that + * the top level API may reliably ignore StringWriter IOExceptions. + * + * @param input CharSequence that is being translated + * @param index int representing the current point of translation + * @param out Writer to translate the text to + * @return int count of codepoints consumed + * @throws IOException if and only if the Writer produces an IOException + */ + public abstract int translate(CharSequence input, int index, Writer out) throws IOException; + + /** + * Helper for non-Writer usage. + * @param input CharSequence to be translated + * @return String output of translation + */ + public final String translate(final CharSequence input) { + if (input == null) { + return null; + } + try { + final StringWriter writer = new StringWriter(input.length() * 2); + translate(input, writer); + return writer.toString(); + } catch (final IOException ioe) { + // this should never ever happen while writing to a StringWriter + throw new RuntimeException(ioe); + } + } + + /** + * Translate an input onto a Writer. This is intentionally final as its algorithm is + * tightly coupled with the abstract method of this class. + * + * @param input CharSequence that is being translated + * @param out Writer to translate the text to + * @throws IOException if and only if the Writer produces an IOException + */ +/** + * Translate an input onto a Writer. This is intentionally final as its algorithm is + * tightly coupled with the abstract method of this class. + * + * @param input + * CharSequence that is being translated + * @param out + * Writer to translate the text to + * @throws IOException + * if and only if the Writer produces an IOException + */ +public final void translate(final java.lang.CharSequence input, final java.io.Writer out) throws java.io.IOException { + if (out == null) { + throw new java.lang.IllegalArgumentException("The Writer must not be null"); + } + { + int pos = 0; + final int len = /* NPEX_NULL_EXP */ + input.length(); + while (pos < len) { + final int consumed = translate(input, pos, out); + if (consumed == 0) { + // inlined implementation of Character.toChars(Character.codePointAt(input, pos)) + // avoids allocating temp char arrays and duplicate checks + char c1 = input.charAt(pos); + out.write(c1); + pos++; + if (java.lang.Character.isHighSurrogate(c1) && (pos < len)) { + char c2 = input.charAt(pos); + if (java.lang.Character.isLowSurrogate(c2)) { + out.write(c2); + pos++; + } + } + continue; + } + // contract with translators is that they have to understand codepoints + // and they just took care of a surrogate pair + for (int pt = 0; pt < consumed; pt++) { + pos += java.lang.Character.charCount(java.lang.Character.codePointAt(input, pos)); + } + } + } +} + + /** + * Helper method to create a merger of this translator with another set of + * translators. Useful in customizing the standard functionality. + * + * @param translators CharSequenceTranslator array of translators to merge with this one + * @return CharSequenceTranslator merging this translator with the others + */ + public final CharSequenceTranslator with(final CharSequenceTranslator... translators) { + final CharSequenceTranslator[] newArray = new CharSequenceTranslator[translators.length + 1]; + newArray[0] = this; + System.arraycopy(translators, 0, newArray, 1, translators.length); + return new AggregateTranslator(newArray); + } + + /** + *

Returns an upper case hexadecimal String for the given + * character.

+ * + * @param codepoint The codepoint to convert. + * @return An upper case hexadecimal String + */ + public static String hex(final int codepoint) { + return Integer.toHexString(codepoint).toUpperCase(Locale.ENGLISH); + } + +} diff --git a/Java/commons-lang-CharSequenceTranslator_80/metadata.json b/Java/commons-lang-CharSequenceTranslator_80/metadata.json new file mode 100644 index 000000000..f9ab1fcbd --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_80/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharSequenceTranslator_80", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java", + "line": 94, + "npe_method": "translate", + "deref_field": "input", + "npe_class": "CharSequenceTranslator", + "repo": "commons-lang", + "bug_id": "CharSequenceTranslator_80" + } +} diff --git a/Java/commons-lang-CharSequenceTranslator_80/npe.json b/Java/commons-lang-CharSequenceTranslator_80/npe.json new file mode 100644 index 000000000..9feee051a --- /dev/null +++ b/Java/commons-lang-CharSequenceTranslator_80/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/text/translate/CharSequenceTranslator.java", + "line": 94, + "npe_method": "translate", + "deref_field": "input", + "npe_class": "CharSequenceTranslator" +} \ No newline at end of file diff --git a/Java/commons-lang-CharSequenceUtils_57/Dockerfile b/Java/commons-lang-CharSequenceUtils_57/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharSequenceUtils_57/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharSequenceUtils_57/buggy.java b/Java/commons-lang-CharSequenceUtils_57/buggy.java new file mode 100644 index 000000000..769987c44 --- /dev/null +++ b/Java/commons-lang-CharSequenceUtils_57/buggy.java @@ -0,0 +1,248 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +/** + *

Operations on {@link CharSequence} that are + * {@code null} safe.

+ * + * @see CharSequence + * @since 3.0 + */ +public class CharSequenceUtils { + + private static final int NOT_FOUND = -1; + + /** + *

{@code CharSequenceUtils} instances should NOT be constructed in + * standard programming.

+ * + *

This constructor is public to permit tools that require a JavaBean + * instance to operate.

+ */ + public CharSequenceUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

Returns a new {@code CharSequence} that is a subsequence of this + * sequence starting with the {@code char} value at the specified index.

+ * + *

This provides the {@code CharSequence} equivalent to {@link String#substring(int)}. + * The length (in {@code char}) of the returned sequence is {@code length() - start}, + * so if {@code start == end} then an empty sequence is returned.

+ * + * @param cs the specified subsequence, null returns null + * @param start the start index, inclusive, valid + * @return a new subsequence, may be null + * @throws IndexOutOfBoundsException if {@code start} is negative or if + * {@code start} is greater than {@code length()} + */ +// ----------------------------------------------------------------------- +/** + *

Returns a new {@code CharSequence} that is a subsequence of this + * sequence starting with the {@code char} value at the specified index.

+ * + *

This provides the {@code CharSequence} equivalent to {@link String#substring(int)}. + * The length (in {@code char}) of the returned sequence is {@code length() - start}, + * so if {@code start == end} then an empty sequence is returned.

+ * + * @param cs + * the specified subsequence, null returns null + * @param start + * the start index, inclusive, valid + * @return a new subsequence, may be null + * @throws IndexOutOfBoundsException + * if {@code start} is negative or if + * {@code start} is greater than {@code length()} + */ +public static java.lang.CharSequence subSequence(final java.lang.CharSequence cs, final int start) { + return /* NPEX_NULL_EXP */ + cs.subSequence(start, cs.length()); +} + + //----------------------------------------------------------------------- + /** + *

Finds the first index in the {@code CharSequence} that matches the + * specified character.

+ * + * @param cs the {@code CharSequence} to be processed, not null + * @param searchChar the char to be searched for + * @param start the start index, negative starts at the string start + * @return the index where the search char was found, -1 if not found + */ + static int indexOf(final CharSequence cs, final int searchChar, int start) { + if (cs instanceof String) { + return ((String) cs).indexOf(searchChar, start); + } + final int sz = cs.length(); + if (start < 0) { + start = 0; + } + for (int i = start; i < sz; i++) { + if (cs.charAt(i) == searchChar) { + return i; + } + } + return NOT_FOUND; + } + + /** + * Used by the indexOf(CharSequence methods) as a green implementation of indexOf. + * + * @param cs the {@code CharSequence} to be processed + * @param searchChar the {@code CharSequence} to be searched for + * @param start the start index + * @return the index where the search sequence was found + */ + static int indexOf(final CharSequence cs, final CharSequence searchChar, final int start) { + return cs.toString().indexOf(searchChar.toString(), start); +// if (cs instanceof String && searchChar instanceof String) { +// // TODO: Do we assume searchChar is usually relatively small; +// // If so then calling toString() on it is better than reverting to +// // the green implementation in the else block +// return ((String) cs).indexOf((String) searchChar, start); +// } else { +// // TODO: Implement rather than convert to String +// return cs.toString().indexOf(searchChar.toString(), start); +// } + } + + /** + *

Finds the last index in the {@code CharSequence} that matches the + * specified character.

+ * + * @param cs the {@code CharSequence} to be processed + * @param searchChar the char to be searched for + * @param start the start index, negative returns -1, beyond length starts at end + * @return the index where the search char was found, -1 if not found + */ + static int lastIndexOf(final CharSequence cs, final int searchChar, int start) { + if (cs instanceof String) { + return ((String) cs).lastIndexOf(searchChar, start); + } + final int sz = cs.length(); + if (start < 0) { + return NOT_FOUND; + } + if (start >= sz) { + start = sz - 1; + } + for (int i = start; i >= 0; --i) { + if (cs.charAt(i) == searchChar) { + return i; + } + } + return NOT_FOUND; + } + + /** + * Used by the lastIndexOf(CharSequence methods) as a green implementation of lastIndexOf + * + * @param cs the {@code CharSequence} to be processed + * @param searchChar the {@code CharSequence} to be searched for + * @param start the start index + * @return the index where the search sequence was found + */ + static int lastIndexOf(final CharSequence cs, final CharSequence searchChar, final int start) { + return cs.toString().lastIndexOf(searchChar.toString(), start); +// if (cs instanceof String && searchChar instanceof String) { +// // TODO: Do we assume searchChar is usually relatively small; +// // If so then calling toString() on it is better than reverting to +// // the green implementation in the else block +// return ((String) cs).lastIndexOf((String) searchChar, start); +// } else { +// // TODO: Implement rather than convert to String +// return cs.toString().lastIndexOf(searchChar.toString(), start); +// } + } + + /** + * Green implementation of toCharArray. + * + * @param cs the {@code CharSequence} to be processed + * @return the resulting char array + */ + static char[] toCharArray(final CharSequence cs) { + if (cs instanceof String) { + return ((String) cs).toCharArray(); + } + final int sz = cs.length(); + final char[] array = new char[cs.length()]; + for (int i = 0; i < sz; i++) { + array[i] = cs.charAt(i); + } + return array; + } + + /** + * Green implementation of regionMatches. + * + * @param cs the {@code CharSequence} to be processed + * @param ignoreCase whether or not to be case insensitive + * @param thisStart the index to start on the {@code cs} CharSequence + * @param substring the {@code CharSequence} to be looked for + * @param start the index to start on the {@code substring} CharSequence + * @param length character length of the region + * @return whether the region matched + */ + static boolean regionMatches(final CharSequence cs, final boolean ignoreCase, final int thisStart, + final CharSequence substring, final int start, final int length) { + if (cs instanceof String && substring instanceof String) { + return ((String) cs).regionMatches(ignoreCase, thisStart, (String) substring, start, length); + } + int index1 = thisStart; + int index2 = start; + int tmpLen = length; + + // Extract these first so we detect NPEs the same as the java.lang.String version + final int srcLen = cs.length() - thisStart; + final int otherLen = substring.length() - start; + + // Check for invalid parameters + if (thisStart < 0 || start < 0 || length < 0) { + return false; + } + + // Check that the regions are long enough + if (srcLen < length || otherLen < length) { + return false; + } + + while (tmpLen-- > 0) { + final char c1 = cs.charAt(index1++); + final char c2 = substring.charAt(index2++); + + if (c1 == c2) { + continue; + } + + if (!ignoreCase) { + return false; + } + + // The same check as in String.regionMatches(): + if (Character.toUpperCase(c1) != Character.toUpperCase(c2) + && Character.toLowerCase(c1) != Character.toLowerCase(c2)) { + return false; + } + } + + return true; + } +} diff --git a/Java/commons-lang-CharSequenceUtils_57/metadata.json b/Java/commons-lang-CharSequenceUtils_57/metadata.json new file mode 100644 index 000000000..5aed548f8 --- /dev/null +++ b/Java/commons-lang-CharSequenceUtils_57/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharSequenceUtils_57", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/CharSequenceUtils.java", + "line": 76, + "npe_method": "subSequence", + "deref_field": "cs", + "npe_class": "CharSequenceUtils", + "repo": "commons-lang", + "bug_id": "CharSequenceUtils_57" + } +} diff --git a/Java/commons-lang-CharSequenceUtils_57/npe.json b/Java/commons-lang-CharSequenceUtils_57/npe.json new file mode 100644 index 000000000..7d185e1a4 --- /dev/null +++ b/Java/commons-lang-CharSequenceUtils_57/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/CharSequenceUtils.java", + "line": 76, + "npe_method": "subSequence", + "deref_field": "cs", + "npe_class": "CharSequenceUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-CharSetUtils_188/Dockerfile b/Java/commons-lang-CharSetUtils_188/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharSetUtils_188/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharSetUtils_188/buggy.java b/Java/commons-lang-CharSetUtils_188/buggy.java new file mode 100644 index 000000000..f76fb5d77 --- /dev/null +++ b/Java/commons-lang-CharSetUtils_188/buggy.java @@ -0,0 +1,286 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +/** + *

Operations on {@code CharSet} instances.

+ * + *

This class handles {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

+ * + *

#ThreadSafe#

+ * @see CharSet + * @since 1.0 + */ +public class CharSetUtils { + + /** + *

CharSetUtils instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code CharSetUtils.evaluateSet(null);}.

+ * + *

This constructor is public to permit tools that require a JavaBean instance + * to operate.

+ */ + public CharSetUtils() { + super(); + } + + // Squeeze + //----------------------------------------------------------------------- + /** + *

Squeezes any repetitions of a character that is mentioned in the + * supplied set.

+ * + *
+     * CharSetUtils.squeeze(null, *)        = null
+     * CharSetUtils.squeeze("", *)          = ""
+     * CharSetUtils.squeeze(*, null)        = *
+     * CharSetUtils.squeeze(*, "")          = *
+     * CharSetUtils.squeeze("hello", "k-p") = "helo"
+     * CharSetUtils.squeeze("hello", "a-e") = "hello"
+     * 
+ * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str the string to squeeze, may be null + * @param set the character set to use for manipulation, may be null + * @return the modified String, {@code null} if null string input + */ + public static String squeeze(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return str; + } + final CharSet chars = CharSet.getInstance(set); + final StringBuilder buffer = new StringBuilder(str.length()); + final char[] chrs = str.toCharArray(); + final int sz = chrs.length; + char lastChar = chrs[0]; + char ch = ' '; + Character inChars = null; + Character notInChars = null; + buffer.append(lastChar); + for (int i = 1; i < sz; i++) { + ch = chrs[i]; + if (ch == lastChar) { + if (inChars != null && ch == inChars) { + continue; + } else { + if (notInChars == null || ch != notInChars) { + if (chars.contains(ch)) { + inChars = ch; + continue; + } else { + notInChars = ch; + } + } + } + } + buffer.append(ch); + lastChar = ch; + } + return buffer.toString(); + } + + // ContainsAny + //----------------------------------------------------------------------- + /** + *

Takes an argument in set-syntax, see evaluateSet, + * and identifies whether any of the characters are present in the specified string.

+ * + *
+     * CharSetUtils.containsAny(null, *)        = false
+     * CharSetUtils.containsAny("", *)          = false
+     * CharSetUtils.containsAny(*, null)        = false
+     * CharSetUtils.containsAny(*, "")          = false
+     * CharSetUtils.containsAny("hello", "k-p") = true
+     * CharSetUtils.containsAny("hello", "a-d") = false
+     * 
+ * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to look for characters in, may be null + * @param set String[] set of characters to identify, may be null + * @return whether or not the characters in the set are in the primary string + * @since 3.2 + */ + public static boolean containsAny(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return false; + } + final CharSet chars = CharSet.getInstance(set); + for (final char c : str.toCharArray()) { + if (chars.contains(c)) { + return true; + } + } + return false; + } + + // Count + //----------------------------------------------------------------------- + /** + *

Takes an argument in set-syntax, see evaluateSet, + * and returns the number of characters present in the specified string.

+ * + *
+     * CharSetUtils.count(null, *)        = 0
+     * CharSetUtils.count("", *)          = 0
+     * CharSetUtils.count(*, null)        = 0
+     * CharSetUtils.count(*, "")          = 0
+     * CharSetUtils.count("hello", "k-p") = 3
+     * CharSetUtils.count("hello", "a-e") = 1
+     * 
+ * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to count characters in, may be null + * @param set String[] set of characters to count, may be null + * @return the character count, zero if null string input + */ + public static int count(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return 0; + } + final CharSet chars = CharSet.getInstance(set); + int count = 0; + for (final char c : str.toCharArray()) { + if (chars.contains(c)) { + count++; + } + } + return count; + } + + // Keep + //----------------------------------------------------------------------- + /** + *

Takes an argument in set-syntax, see evaluateSet, + * and keeps any of characters present in the specified string.

+ * + *
+     * CharSetUtils.keep(null, *)        = null
+     * CharSetUtils.keep("", *)          = ""
+     * CharSetUtils.keep(*, null)        = ""
+     * CharSetUtils.keep(*, "")          = ""
+     * CharSetUtils.keep("hello", "hl")  = "hll"
+     * CharSetUtils.keep("hello", "le")  = "ell"
+     * 
+ * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to keep characters from, may be null + * @param set String[] set of characters to keep, may be null + * @return the modified String, {@code null} if null string input + * @since 2.0 + */ +// Keep +// ----------------------------------------------------------------------- +/** + *

Takes an argument in set-syntax, see evaluateSet, + * and keeps any of characters present in the specified string.

+ * + *
+ * CharSetUtils.keep(null, *)        = null
+ * CharSetUtils.keep("", *)          = ""
+ * CharSetUtils.keep(*, null)        = ""
+ * CharSetUtils.keep(*, "")          = ""
+ * CharSetUtils.keep("hello", "hl")  = "hll"
+ * CharSetUtils.keep("hello", "le")  = "ell"
+ * 
+ * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str + * String to keep characters from, may be null + * @param set + * String[] set of characters to keep, may be null + * @return the modified String, {@code null} if null string input + * @since 2.0 + */ +public static java.lang.String keep(final java.lang.String str, final java.lang.String... set) { + { + if (/* NPEX_NULL_EXP */ + str.isEmpty() || org.apache.commons.lang3.CharSetUtils.deepEmpty(set)) { + return org.apache.commons.lang3.StringUtils.EMPTY; + } + return org.apache.commons.lang3.CharSetUtils.modify(str, set, true); + } +} + + // Delete + //----------------------------------------------------------------------- + /** + *

Takes an argument in set-syntax, see evaluateSet, + * and deletes any of characters present in the specified string.

+ * + *
+     * CharSetUtils.delete(null, *)        = null
+     * CharSetUtils.delete("", *)          = ""
+     * CharSetUtils.delete(*, null)        = *
+     * CharSetUtils.delete(*, "")          = *
+     * CharSetUtils.delete("hello", "hl")  = "eo"
+     * CharSetUtils.delete("hello", "le")  = "ho"
+     * 
+ * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to delete characters from, may be null + * @param set String[] set of characters to delete, may be null + * @return the modified String, {@code null} if null string input + */ + public static String delete(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return str; + } + return modify(str, set, false); + } + + //----------------------------------------------------------------------- + /** + * Implementation of delete and keep + * + * @param str String to modify characters within + * @param set String[] set of characters to modify + * @param expect whether to evaluate on match, or non-match + * @return the modified String, not null + */ + private static String modify(final String str, final String[] set, final boolean expect) { + final CharSet chars = CharSet.getInstance(set); + final StringBuilder buffer = new StringBuilder(str.length()); + final char[] chrs = str.toCharArray(); + final int sz = chrs.length; + for(int i=0; i traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharSetUtils_254/buggy.java b/Java/commons-lang-CharSetUtils_254/buggy.java new file mode 100644 index 000000000..ba2564b05 --- /dev/null +++ b/Java/commons-lang-CharSetUtils_254/buggy.java @@ -0,0 +1,272 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +/** + *

Operations on {@code CharSet} instances.

+ * + *

This class handles {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

+ * + *

#ThreadSafe#

+ * @see CharSet + * @since 1.0 + */ +public class CharSetUtils { + + /** + *

CharSetUtils instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code CharSetUtils.evaluateSet(null);}.

+ * + *

This constructor is public to permit tools that require a JavaBean instance + * to operate.

+ */ + public CharSetUtils() { + super(); + } + + // Squeeze + //----------------------------------------------------------------------- + /** + *

Squeezes any repetitions of a character that is mentioned in the + * supplied set.

+ * + *
+     * CharSetUtils.squeeze(null, *)        = null
+     * CharSetUtils.squeeze("", *)          = ""
+     * CharSetUtils.squeeze(*, null)        = *
+     * CharSetUtils.squeeze(*, "")          = *
+     * CharSetUtils.squeeze("hello", "k-p") = "helo"
+     * CharSetUtils.squeeze("hello", "a-e") = "hello"
+     * 
+ * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str the string to squeeze, may be null + * @param set the character set to use for manipulation, may be null + * @return the modified String, {@code null} if null string input + */ + public static String squeeze(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return str; + } + final CharSet chars = CharSet.getInstance(set); + final StringBuilder buffer = new StringBuilder(str.length()); + final char[] chrs = str.toCharArray(); + final int sz = chrs.length; + char lastChar = chrs[0]; + char ch = ' '; + Character inChars = null; + Character notInChars = null; + buffer.append(lastChar); + for (int i = 1; i < sz; i++) { + ch = chrs[i]; + if (ch == lastChar) { + if (inChars != null && ch == inChars) { + continue; + } else { + if (notInChars == null || ch != notInChars) { + if (chars.contains(ch)) { + inChars = ch; + continue; + } else { + notInChars = ch; + } + } + } + } + buffer.append(ch); + lastChar = ch; + } + return buffer.toString(); + } + + // ContainsAny + //----------------------------------------------------------------------- + /** + *

Takes an argument in set-syntax, see evaluateSet, + * and identifies whether any of the characters are present in the specified string.

+ * + *
+     * CharSetUtils.containsAny(null, *)        = false
+     * CharSetUtils.containsAny("", *)          = false
+     * CharSetUtils.containsAny(*, null)        = false
+     * CharSetUtils.containsAny(*, "")          = false
+     * CharSetUtils.containsAny("hello", "k-p") = true
+     * CharSetUtils.containsAny("hello", "a-d") = false
+     * 
+ * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to look for characters in, may be null + * @param set String[] set of characters to identify, may be null + * @return whether or not the characters in the set are in the primary string + * @since 3.2 + */ + public static boolean containsAny(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return false; + } + final CharSet chars = CharSet.getInstance(set); + for (final char c : str.toCharArray()) { + if (chars.contains(c)) { + return true; + } + } + return false; + } + + // Count + //----------------------------------------------------------------------- + /** + *

Takes an argument in set-syntax, see evaluateSet, + * and returns the number of characters present in the specified string.

+ * + *
+     * CharSetUtils.count(null, *)        = 0
+     * CharSetUtils.count("", *)          = 0
+     * CharSetUtils.count(*, null)        = 0
+     * CharSetUtils.count(*, "")          = 0
+     * CharSetUtils.count("hello", "k-p") = 3
+     * CharSetUtils.count("hello", "a-e") = 1
+     * 
+ * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to count characters in, may be null + * @param set String[] set of characters to count, may be null + * @return the character count, zero if null string input + */ + public static int count(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return 0; + } + final CharSet chars = CharSet.getInstance(set); + int count = 0; + for (final char c : str.toCharArray()) { + if (chars.contains(c)) { + count++; + } + } + return count; + } + + // Keep + //----------------------------------------------------------------------- + /** + *

Takes an argument in set-syntax, see evaluateSet, + * and keeps any of characters present in the specified string.

+ * + *
+     * CharSetUtils.keep(null, *)        = null
+     * CharSetUtils.keep("", *)          = ""
+     * CharSetUtils.keep(*, null)        = ""
+     * CharSetUtils.keep(*, "")          = ""
+     * CharSetUtils.keep("hello", "hl")  = "hll"
+     * CharSetUtils.keep("hello", "le")  = "ell"
+     * 
+ * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to keep characters from, may be null + * @param set String[] set of characters to keep, may be null + * @return the modified String, {@code null} if null string input + * @since 2.0 + */ + public static String keep(final String str, final String... set) { + if (str == null) { + return null; + } + if (str.isEmpty() || deepEmpty(set)) { + return StringUtils.EMPTY; + } + return modify(str, set, true); + } + + // Delete + //----------------------------------------------------------------------- + /** + *

Takes an argument in set-syntax, see evaluateSet, + * and deletes any of characters present in the specified string.

+ * + *
+     * CharSetUtils.delete(null, *)        = null
+     * CharSetUtils.delete("", *)          = ""
+     * CharSetUtils.delete(*, null)        = *
+     * CharSetUtils.delete(*, "")          = *
+     * CharSetUtils.delete("hello", "hl")  = "eo"
+     * CharSetUtils.delete("hello", "le")  = "ho"
+     * 
+ * + * @see CharSet#getInstance(java.lang.String...) for set-syntax. + * @param str String to delete characters from, may be null + * @param set String[] set of characters to delete, may be null + * @return the modified String, {@code null} if null string input + */ + public static String delete(final String str, final String... set) { + if (StringUtils.isEmpty(str) || deepEmpty(set)) { + return str; + } + return modify(str, set, false); + } + + //----------------------------------------------------------------------- + /** + * Implementation of delete and keep + * + * @param str String to modify characters within + * @param set String[] set of characters to modify + * @param expect whether to evaluate on match, or non-match + * @return the modified String, not null + */ + private static String modify(final String str, final String[] set, final boolean expect) { + final CharSet chars = CharSet.getInstance(set); + final StringBuilder buffer = new StringBuilder(str.length()); + final char[] chrs = str.toCharArray(); + final int sz = chrs.length; + for(int i=0; i traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharSet_156/buggy.java b/Java/commons-lang-CharSet_156/buggy.java new file mode 100644 index 000000000..303c49328 --- /dev/null +++ b/Java/commons-lang-CharSet_156/buggy.java @@ -0,0 +1,358 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + *

A set of characters.

+ * + *

Instances are immutable, but instances of subclasses may not be.

+ * + *

#ThreadSafe#

+ * @since 1.0 + */ +public class CharSet implements Serializable { + + /** + * Required for serialization support. Lang version 2.0. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 5947847346149275958L; + + /** + * A CharSet defining no characters. + * @since 2.0 + */ + public static final CharSet EMPTY = new CharSet((String) null); + + /** + * A CharSet defining ASCII alphabetic characters "a-zA-Z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA = new CharSet("a-zA-Z"); + + /** + * A CharSet defining ASCII alphabetic characters "a-z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA_LOWER = new CharSet("a-z"); + + /** + * A CharSet defining ASCII alphabetic characters "A-Z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA_UPPER = new CharSet("A-Z"); + + /** + * A CharSet defining ASCII alphabetic characters "0-9". + * @since 2.0 + */ + public static final CharSet ASCII_NUMERIC = new CharSet("0-9"); + + /** + * A Map of the common cases used in the factory. + * Subclasses can add more common patterns if desired + * @since 2.0 + */ + protected static final Map COMMON = Collections.synchronizedMap(new HashMap()); + + static { + COMMON.put(null, EMPTY); + COMMON.put(StringUtils.EMPTY, EMPTY); + COMMON.put("a-zA-Z", ASCII_ALPHA); + COMMON.put("A-Za-z", ASCII_ALPHA); + COMMON.put("a-z", ASCII_ALPHA_LOWER); + COMMON.put("A-Z", ASCII_ALPHA_UPPER); + COMMON.put("0-9", ASCII_NUMERIC); + } + + /** The set of CharRange objects. */ + private final Set set = Collections.synchronizedSet(new HashSet()); + + //----------------------------------------------------------------------- + /** + *

Factory method to create a new CharSet using a special syntax.

+ * + *
    + *
  • {@code null} or empty string ("") + * - set containing no characters
  • + *
  • Single character, such as "a" + * - set containing just that character
  • + *
  • Multi character, such as "a-e" + * - set containing characters from one character to the other
  • + *
  • Negated, such as "^a" or "^a-e" + * - set containing all characters except those defined
  • + *
  • Combinations, such as "abe-g" + * - set containing all the characters from the individual sets
  • + *
+ * + *

The matching order is:

+ *
    + *
  1. Negated multi character range, such as "^a-e" + *
  2. Ordinary multi character range, such as "a-e" + *
  3. Negated single character, such as "^a" + *
  4. Ordinary single character, such as "a" + *
+ * + *

Matching works left to right. Once a match is found the + * search starts again from the next character.

+ * + *

If the same range is defined twice using the same syntax, only + * one range will be kept. + * Thus, "a-ca-c" creates only one range of "a-c".

+ * + *

If the start and end of a range are in the wrong order, + * they are reversed. Thus "a-e" is the same as "e-a". + * As a result, "a-ee-a" would create only one range, + * as the "a-e" and "e-a" are the same.

+ * + *

The set of characters represented is the union of the specified ranges.

+ * + *

There are two ways to add a literal negation character ({@code ^}):

+ *
    + *
  • As the last character in a string, e.g. {@code CharSet.getInstance("a-z^")}
  • + *
  • As a separate element, e.g. {@code CharSet.getInstance("^","a-z")}
  • + *
+ * + *

Examples using the negation character:

+ *
+     *     CharSet.getInstance("^a-c").contains('a') = false
+     *     CharSet.getInstance("^a-c").contains('d') = true
+     *     CharSet.getInstance("^^a-c").contains('a') = true // (only '^' is negated)
+     *     CharSet.getInstance("^^a-c").contains('^') = false
+     *     CharSet.getInstance("^a-cd-f").contains('d') = true 
+     *     CharSet.getInstance("a-c^").contains('^') = true
+     *     CharSet.getInstance("^", "a-c").contains('^') = true
+     * 
+ * + *

All CharSet objects returned by this method will be immutable.

+ * + * @param setStrs Strings to merge into the set, may be null + * @return a CharSet instance + * @since 2.4 + */ +// ----------------------------------------------------------------------- +/** + *

Factory method to create a new CharSet using a special syntax.

+ * + *
    + *
  • {@code null} or empty string ("") + * - set containing no characters
  • + *
  • Single character, such as "a" + * - set containing just that character
  • + *
  • Multi character, such as "a-e" + * - set containing characters from one character to the other
  • + *
  • Negated, such as "^a" or "^a-e" + * - set containing all characters except those defined
  • + *
  • Combinations, such as "abe-g" + * - set containing all the characters from the individual sets
  • + *
+ * + *

The matching order is:

+ *
    + *
  1. Negated multi character range, such as "^a-e" + *
  2. Ordinary multi character range, such as "a-e" + *
  3. Negated single character, such as "^a" + *
  4. Ordinary single character, such as "a" + *
+ * + *

Matching works left to right. Once a match is found the + * search starts again from the next character.

+ * + *

If the same range is defined twice using the same syntax, only + * one range will be kept. + * Thus, "a-ca-c" creates only one range of "a-c".

+ * + *

If the start and end of a range are in the wrong order, + * they are reversed. Thus "a-e" is the same as "e-a". + * As a result, "a-ee-a" would create only one range, + * as the "a-e" and "e-a" are the same.

+ * + *

The set of characters represented is the union of the specified ranges.

+ * + *

There are two ways to add a literal negation character ({@code ^}):

+ *
    + *
  • As the last character in a string, e.g. {@code CharSet.getInstance("a-z^")}
  • + *
  • As a separate element, e.g. {@code CharSet.getInstance("^","a-z")}
  • + *
+ * + *

Examples using the negation character:

+ *
+ * CharSet.getInstance("^a-c").contains('a') = false
+ * CharSet.getInstance("^a-c").contains('d') = true
+ * CharSet.getInstance("^^a-c").contains('a') = true // (only '^' is negated)
+ * CharSet.getInstance("^^a-c").contains('^') = false
+ * CharSet.getInstance("^a-cd-f").contains('d') = true
+ * CharSet.getInstance("a-c^").contains('^') = true
+ * CharSet.getInstance("^", "a-c").contains('^') = true
+ * 
+ * + *

All CharSet objects returned by this method will be immutable.

+ * + * @param setStrs + * Strings to merge into the set, may be null + * @return a CharSet instance + * @since 2.4 + */ +public static org.apache.commons.lang3.CharSet getInstance(final java.lang.String... setStrs) { + { + if (/* NPEX_NULL_EXP */ + setStrs.length == 1) { + final org.apache.commons.lang3.CharSet common = org.apache.commons.lang3.CharSet.COMMON.get(setStrs[0]); + if (common != null) { + return common; + } + } + return new org.apache.commons.lang3.CharSet(setStrs); + } +} + + //----------------------------------------------------------------------- + /** + *

Constructs a new CharSet using the set syntax. + * Each string is merged in with the set.

+ * + * @param set Strings to merge into the initial set + * @throws NullPointerException if set is {@code null} + */ + protected CharSet(final String... set) { + super(); + final int sz = set.length; + for (int i = 0; i < sz; i++) { + add(set[i]); + } + } + + //----------------------------------------------------------------------- + /** + *

Add a set definition string to the {@code CharSet}.

+ * + * @param str set definition string + */ + protected void add(final String str) { + if (str == null) { + return; + } + + final int len = str.length(); + int pos = 0; + while (pos < len) { + final int remainder = len - pos; + if (remainder >= 4 && str.charAt(pos) == '^' && str.charAt(pos + 2) == '-') { + // negated range + set.add(CharRange.isNotIn(str.charAt(pos + 1), str.charAt(pos + 3))); + pos += 4; + } else if (remainder >= 3 && str.charAt(pos + 1) == '-') { + // range + set.add(CharRange.isIn(str.charAt(pos), str.charAt(pos + 2))); + pos += 3; + } else if (remainder >= 2 && str.charAt(pos) == '^') { + // negated char + set.add(CharRange.isNot(str.charAt(pos + 1))); + pos += 2; + } else { + // char + set.add(CharRange.is(str.charAt(pos))); + pos += 1; + } + } + } + + //----------------------------------------------------------------------- + /** + *

Gets the internal set as an array of CharRange objects.

+ * + * @return an array of immutable CharRange objects + * @since 2.0 + */ +// NOTE: This is no longer public as CharRange is no longer a public class. +// It may be replaced when CharSet moves to Range. + /*public*/ CharRange[] getCharRanges() { + return set.toArray(new CharRange[set.size()]); + } + + //----------------------------------------------------------------------- + /** + *

Does the {@code CharSet} contain the specified + * character {@code ch}.

+ * + * @param ch the character to check for + * @return {@code true} if the set contains the characters + */ + public boolean contains(final char ch) { + for (final CharRange range : set) { + if (range.contains(ch)) { + return true; + } + } + return false; + } + + // Basics + //----------------------------------------------------------------------- + /** + *

Compares two {@code CharSet} objects, returning true if they represent + * exactly the same set of characters defined in the same way.

+ * + *

The two sets {@code abc} and {@code a-c} are not + * equal according to this method.

+ * + * @param obj the object to compare to + * @return true if equal + * @since 2.0 + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CharSet == false) { + return false; + } + final CharSet other = (CharSet) obj; + return set.equals(other.set); + } + + /** + *

Gets a hash code compatible with the equals method.

+ * + * @return a suitable hash code + * @since 2.0 + */ + @Override + public int hashCode() { + return 89 + set.hashCode(); + } + + /** + *

Gets a string representation of the set.

+ * + * @return string representation of the set + */ + @Override + public String toString() { + return set.toString(); + } + +} diff --git a/Java/commons-lang-CharSet_156/metadata.json b/Java/commons-lang-CharSet_156/metadata.json new file mode 100644 index 000000000..74c2de960 --- /dev/null +++ b/Java/commons-lang-CharSet_156/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharSet_156", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/CharSet.java", + "line": 221, + "npe_method": "getInstance", + "deref_field": "setStrs", + "npe_class": "CharSet", + "repo": "commons-lang", + "bug_id": "CharSet_156" + } +} diff --git a/Java/commons-lang-CharSet_156/npe.json b/Java/commons-lang-CharSet_156/npe.json new file mode 100644 index 000000000..0064e7d04 --- /dev/null +++ b/Java/commons-lang-CharSet_156/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/CharSet.java", + "line": 221, + "npe_method": "getInstance", + "deref_field": "setStrs", + "npe_class": "CharSet" +} \ No newline at end of file diff --git a/Java/commons-lang-CharSet_161/Dockerfile b/Java/commons-lang-CharSet_161/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharSet_161/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharSet_161/buggy.java b/Java/commons-lang-CharSet_161/buggy.java new file mode 100644 index 000000000..816508074 --- /dev/null +++ b/Java/commons-lang-CharSet_161/buggy.java @@ -0,0 +1,359 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + *

A set of characters.

+ * + *

Instances are immutable, but instances of subclasses may not be.

+ * + *

#ThreadSafe#

+ * @since 1.0 + */ +public class CharSet implements Serializable { + + /** + * Required for serialization support. Lang version 2.0. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 5947847346149275958L; + + /** + * A CharSet defining no characters. + * @since 2.0 + */ + public static final CharSet EMPTY = new CharSet((String) null); + + /** + * A CharSet defining ASCII alphabetic characters "a-zA-Z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA = new CharSet("a-zA-Z"); + + /** + * A CharSet defining ASCII alphabetic characters "a-z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA_LOWER = new CharSet("a-z"); + + /** + * A CharSet defining ASCII alphabetic characters "A-Z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA_UPPER = new CharSet("A-Z"); + + /** + * A CharSet defining ASCII alphabetic characters "0-9". + * @since 2.0 + */ + public static final CharSet ASCII_NUMERIC = new CharSet("0-9"); + + /** + * A Map of the common cases used in the factory. + * Subclasses can add more common patterns if desired + * @since 2.0 + */ + protected static final Map COMMON = Collections.synchronizedMap(new HashMap()); + + static { + COMMON.put(null, EMPTY); + COMMON.put(StringUtils.EMPTY, EMPTY); + COMMON.put("a-zA-Z", ASCII_ALPHA); + COMMON.put("A-Za-z", ASCII_ALPHA); + COMMON.put("a-z", ASCII_ALPHA_LOWER); + COMMON.put("A-Z", ASCII_ALPHA_UPPER); + COMMON.put("0-9", ASCII_NUMERIC); + } + + /** The set of CharRange objects. */ + private final Set set = Collections.synchronizedSet(new HashSet()); + + //----------------------------------------------------------------------- + /** + *

Factory method to create a new CharSet using a special syntax.

+ * + *
    + *
  • {@code null} or empty string ("") + * - set containing no characters
  • + *
  • Single character, such as "a" + * - set containing just that character
  • + *
  • Multi character, such as "a-e" + * - set containing characters from one character to the other
  • + *
  • Negated, such as "^a" or "^a-e" + * - set containing all characters except those defined
  • + *
  • Combinations, such as "abe-g" + * - set containing all the characters from the individual sets
  • + *
+ * + *

The matching order is:

+ *
    + *
  1. Negated multi character range, such as "^a-e" + *
  2. Ordinary multi character range, such as "a-e" + *
  3. Negated single character, such as "^a" + *
  4. Ordinary single character, such as "a" + *
+ * + *

Matching works left to right. Once a match is found the + * search starts again from the next character.

+ * + *

If the same range is defined twice using the same syntax, only + * one range will be kept. + * Thus, "a-ca-c" creates only one range of "a-c".

+ * + *

If the start and end of a range are in the wrong order, + * they are reversed. Thus "a-e" is the same as "e-a". + * As a result, "a-ee-a" would create only one range, + * as the "a-e" and "e-a" are the same.

+ * + *

The set of characters represented is the union of the specified ranges.

+ * + *

There are two ways to add a literal negation character ({@code ^}):

+ *
    + *
  • As the last character in a string, e.g. {@code CharSet.getInstance("a-z^")}
  • + *
  • As a separate element, e.g. {@code CharSet.getInstance("^","a-z")}
  • + *
+ * + *

Examples using the negation character:

+ *
+     *     CharSet.getInstance("^a-c").contains('a') = false
+     *     CharSet.getInstance("^a-c").contains('d') = true
+     *     CharSet.getInstance("^^a-c").contains('a') = true // (only '^' is negated)
+     *     CharSet.getInstance("^^a-c").contains('^') = false
+     *     CharSet.getInstance("^a-cd-f").contains('d') = true 
+     *     CharSet.getInstance("a-c^").contains('^') = true
+     *     CharSet.getInstance("^", "a-c").contains('^') = true
+     * 
+ * + *

All CharSet objects returned by this method will be immutable.

+ * + * @param setStrs Strings to merge into the set, may be null + * @return a CharSet instance + * @since 2.4 + */ +// ----------------------------------------------------------------------- +/** + *

Factory method to create a new CharSet using a special syntax.

+ * + *
    + *
  • {@code null} or empty string ("") + * - set containing no characters
  • + *
  • Single character, such as "a" + * - set containing just that character
  • + *
  • Multi character, such as "a-e" + * - set containing characters from one character to the other
  • + *
  • Negated, such as "^a" or "^a-e" + * - set containing all characters except those defined
  • + *
  • Combinations, such as "abe-g" + * - set containing all the characters from the individual sets
  • + *
+ * + *

The matching order is:

+ *
    + *
  1. Negated multi character range, such as "^a-e" + *
  2. Ordinary multi character range, such as "a-e" + *
  3. Negated single character, such as "^a" + *
  4. Ordinary single character, such as "a" + *
+ * + *

Matching works left to right. Once a match is found the + * search starts again from the next character.

+ * + *

If the same range is defined twice using the same syntax, only + * one range will be kept. + * Thus, "a-ca-c" creates only one range of "a-c".

+ * + *

If the start and end of a range are in the wrong order, + * they are reversed. Thus "a-e" is the same as "e-a". + * As a result, "a-ee-a" would create only one range, + * as the "a-e" and "e-a" are the same.

+ * + *

The set of characters represented is the union of the specified ranges.

+ * + *

There are two ways to add a literal negation character ({@code ^}):

+ *
    + *
  • As the last character in a string, e.g. {@code CharSet.getInstance("a-z^")}
  • + *
  • As a separate element, e.g. {@code CharSet.getInstance("^","a-z")}
  • + *
+ * + *

Examples using the negation character:

+ *
+ * CharSet.getInstance("^a-c").contains('a') = false
+ * CharSet.getInstance("^a-c").contains('d') = true
+ * CharSet.getInstance("^^a-c").contains('a') = true // (only '^' is negated)
+ * CharSet.getInstance("^^a-c").contains('^') = false
+ * CharSet.getInstance("^a-cd-f").contains('d') = true
+ * CharSet.getInstance("a-c^").contains('^') = true
+ * CharSet.getInstance("^", "a-c").contains('^') = true
+ * 
+ * + *

All CharSet objects returned by this method will be immutable.

+ * + * @param setStrs + * Strings to merge into the set, may be null + * @return a CharSet instance + * @since 2.4 + */ +public static org.apache.commons.lang3.CharSet getInstance(final java.lang.String... setStrs) { + if (setStrs == null) { + return null; + } + if (setStrs.length == 1) { + final org.apache.commons.lang3.CharSet common = org.apache.commons.lang3.CharSet.COMMON.get(setStrs[0]); + { + return /* NPEX_NULL_EXP */ + common; + } + } + return new org.apache.commons.lang3.CharSet(setStrs); +} + + //----------------------------------------------------------------------- + /** + *

Constructs a new CharSet using the set syntax. + * Each string is merged in with the set.

+ * + * @param set Strings to merge into the initial set + * @throws NullPointerException if set is {@code null} + */ + protected CharSet(final String... set) { + super(); + final int sz = set.length; + for (int i = 0; i < sz; i++) { + add(set[i]); + } + } + + //----------------------------------------------------------------------- + /** + *

Add a set definition string to the {@code CharSet}.

+ * + * @param str set definition string + */ + protected void add(final String str) { + if (str == null) { + return; + } + + final int len = str.length(); + int pos = 0; + while (pos < len) { + final int remainder = len - pos; + if (remainder >= 4 && str.charAt(pos) == '^' && str.charAt(pos + 2) == '-') { + // negated range + set.add(CharRange.isNotIn(str.charAt(pos + 1), str.charAt(pos + 3))); + pos += 4; + } else if (remainder >= 3 && str.charAt(pos + 1) == '-') { + // range + set.add(CharRange.isIn(str.charAt(pos), str.charAt(pos + 2))); + pos += 3; + } else if (remainder >= 2 && str.charAt(pos) == '^') { + // negated char + set.add(CharRange.isNot(str.charAt(pos + 1))); + pos += 2; + } else { + // char + set.add(CharRange.is(str.charAt(pos))); + pos += 1; + } + } + } + + //----------------------------------------------------------------------- + /** + *

Gets the internal set as an array of CharRange objects.

+ * + * @return an array of immutable CharRange objects + * @since 2.0 + */ +// NOTE: This is no longer public as CharRange is no longer a public class. +// It may be replaced when CharSet moves to Range. + /*public*/ CharRange[] getCharRanges() { + return set.toArray(new CharRange[set.size()]); + } + + //----------------------------------------------------------------------- + /** + *

Does the {@code CharSet} contain the specified + * character {@code ch}.

+ * + * @param ch the character to check for + * @return {@code true} if the set contains the characters + */ + public boolean contains(final char ch) { + for (final CharRange range : set) { + if (range.contains(ch)) { + return true; + } + } + return false; + } + + // Basics + //----------------------------------------------------------------------- + /** + *

Compares two {@code CharSet} objects, returning true if they represent + * exactly the same set of characters defined in the same way.

+ * + *

The two sets {@code abc} and {@code a-c} are not + * equal according to this method.

+ * + * @param obj the object to compare to + * @return true if equal + * @since 2.0 + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CharSet == false) { + return false; + } + final CharSet other = (CharSet) obj; + return set.equals(other.set); + } + + /** + *

Gets a hash code compatible with the equals method.

+ * + * @return a suitable hash code + * @since 2.0 + */ + @Override + public int hashCode() { + return 89 + set.hashCode(); + } + + /** + *

Gets a string representation of the set.

+ * + * @return string representation of the set + */ + @Override + public String toString() { + return set.toString(); + } + +} diff --git a/Java/commons-lang-CharSet_161/metadata.json b/Java/commons-lang-CharSet_161/metadata.json new file mode 100644 index 000000000..44629d617 --- /dev/null +++ b/Java/commons-lang-CharSet_161/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharSet_161", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/CharSet.java", + "line": 226, + "npe_method": "getInstance", + "deref_field": "common", + "npe_class": "CharSet", + "repo": "commons-lang", + "bug_id": "CharSet_161" + } +} diff --git a/Java/commons-lang-CharSet_161/npe.json b/Java/commons-lang-CharSet_161/npe.json new file mode 100644 index 000000000..86d0d1c8c --- /dev/null +++ b/Java/commons-lang-CharSet_161/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/CharSet.java", + "line": 226, + "npe_method": "getInstance", + "deref_field": "common", + "npe_class": "CharSet" +} \ No newline at end of file diff --git a/Java/commons-lang-CharSet_191/Dockerfile b/Java/commons-lang-CharSet_191/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharSet_191/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharSet_191/buggy.java b/Java/commons-lang-CharSet_191/buggy.java new file mode 100644 index 000000000..6f2319597 --- /dev/null +++ b/Java/commons-lang-CharSet_191/buggy.java @@ -0,0 +1,301 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +import java.io.Serializable; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +/** + *

A set of characters.

+ * + *

Instances are immutable, but instances of subclasses may not be.

+ * + *

#ThreadSafe#

+ * @since 1.0 + */ +public class CharSet implements Serializable { + + /** + * Required for serialization support. Lang version 2.0. + * + * @see java.io.Serializable + */ + private static final long serialVersionUID = 5947847346149275958L; + + /** + * A CharSet defining no characters. + * @since 2.0 + */ + public static final CharSet EMPTY = new CharSet((String) null); + + /** + * A CharSet defining ASCII alphabetic characters "a-zA-Z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA = new CharSet("a-zA-Z"); + + /** + * A CharSet defining ASCII alphabetic characters "a-z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA_LOWER = new CharSet("a-z"); + + /** + * A CharSet defining ASCII alphabetic characters "A-Z". + * @since 2.0 + */ + public static final CharSet ASCII_ALPHA_UPPER = new CharSet("A-Z"); + + /** + * A CharSet defining ASCII alphabetic characters "0-9". + * @since 2.0 + */ + public static final CharSet ASCII_NUMERIC = new CharSet("0-9"); + + /** + * A Map of the common cases used in the factory. + * Subclasses can add more common patterns if desired + * @since 2.0 + */ + protected static final Map COMMON = Collections.synchronizedMap(new HashMap()); + + static { + COMMON.put(null, EMPTY); + COMMON.put(StringUtils.EMPTY, EMPTY); + COMMON.put("a-zA-Z", ASCII_ALPHA); + COMMON.put("A-Za-z", ASCII_ALPHA); + COMMON.put("a-z", ASCII_ALPHA_LOWER); + COMMON.put("A-Z", ASCII_ALPHA_UPPER); + COMMON.put("0-9", ASCII_NUMERIC); + } + + /** The set of CharRange objects. */ + private final Set set = Collections.synchronizedSet(new HashSet()); + + //----------------------------------------------------------------------- + /** + *

Factory method to create a new CharSet using a special syntax.

+ * + *
    + *
  • {@code null} or empty string ("") + * - set containing no characters
  • + *
  • Single character, such as "a" + * - set containing just that character
  • + *
  • Multi character, such as "a-e" + * - set containing characters from one character to the other
  • + *
  • Negated, such as "^a" or "^a-e" + * - set containing all characters except those defined
  • + *
  • Combinations, such as "abe-g" + * - set containing all the characters from the individual sets
  • + *
+ * + *

The matching order is:

+ *
    + *
  1. Negated multi character range, such as "^a-e" + *
  2. Ordinary multi character range, such as "a-e" + *
  3. Negated single character, such as "^a" + *
  4. Ordinary single character, such as "a" + *
+ * + *

Matching works left to right. Once a match is found the + * search starts again from the next character.

+ * + *

If the same range is defined twice using the same syntax, only + * one range will be kept. + * Thus, "a-ca-c" creates only one range of "a-c".

+ * + *

If the start and end of a range are in the wrong order, + * they are reversed. Thus "a-e" is the same as "e-a". + * As a result, "a-ee-a" would create only one range, + * as the "a-e" and "e-a" are the same.

+ * + *

The set of characters represented is the union of the specified ranges.

+ * + *

There are two ways to add a literal negation character ({@code ^}):

+ *
    + *
  • As the last character in a string, e.g. {@code CharSet.getInstance("a-z^")}
  • + *
  • As a separate element, e.g. {@code CharSet.getInstance("^","a-z")}
  • + *
+ * + *

Examples using the negation character:

+ *
+     *     CharSet.getInstance("^a-c").contains('a') = false
+     *     CharSet.getInstance("^a-c").contains('d') = true
+     *     CharSet.getInstance("^^a-c").contains('a') = true // (only '^' is negated)
+     *     CharSet.getInstance("^^a-c").contains('^') = false
+     *     CharSet.getInstance("^a-cd-f").contains('d') = true 
+     *     CharSet.getInstance("a-c^").contains('^') = true
+     *     CharSet.getInstance("^", "a-c").contains('^') = true
+     * 
+ * + *

All CharSet objects returned by this method will be immutable.

+ * + * @param setStrs Strings to merge into the set, may be null + * @return a CharSet instance + * @since 2.4 + */ + public static CharSet getInstance(final String... setStrs) { + if (setStrs == null) { + return null; + } + if (setStrs.length == 1) { + final CharSet common = COMMON.get(setStrs[0]); + if (common != null) { + return common; + } + } + return new CharSet(setStrs); + } + + //----------------------------------------------------------------------- + /** + *

Constructs a new CharSet using the set syntax. + * Each string is merged in with the set.

+ * + * @param set Strings to merge into the initial set + * @throws NullPointerException if set is {@code null} + */ + protected CharSet(final String... set) { + super(); + final int sz = set.length; + for (int i = 0; i < sz; i++) { + add(set[i]); + } + } + + //----------------------------------------------------------------------- + /** + *

Add a set definition string to the {@code CharSet}.

+ * + * @param str set definition string + */ +// ----------------------------------------------------------------------- +/** + *

Add a set definition string to the {@code CharSet}.

+ * + * @param str + * set definition string + */ +protected void add(final java.lang.String str) { + { + final int len = /* NPEX_NULL_EXP */ + str.length(); + int pos = 0; + while (pos < len) { + final int remainder = len - pos; + if (((remainder >= 4) && (str.charAt(pos) == '^')) && (str.charAt(pos + 2) == '-')) { + // negated range + set.add(org.apache.commons.lang3.CharRange.isNotIn(str.charAt(pos + 1), str.charAt(pos + 3))); + pos += 4; + } else if ((remainder >= 3) && (str.charAt(pos + 1) == '-')) { + // range + set.add(org.apache.commons.lang3.CharRange.isIn(str.charAt(pos), str.charAt(pos + 2))); + pos += 3; + } else if ((remainder >= 2) && (str.charAt(pos) == '^')) { + // negated char + set.add(org.apache.commons.lang3.CharRange.isNot(str.charAt(pos + 1))); + pos += 2; + } else { + // char + set.add(org.apache.commons.lang3.CharRange.is(str.charAt(pos))); + pos += 1; + } + } + } +} + + //----------------------------------------------------------------------- + /** + *

Gets the internal set as an array of CharRange objects.

+ * + * @return an array of immutable CharRange objects + * @since 2.0 + */ +// NOTE: This is no longer public as CharRange is no longer a public class. +// It may be replaced when CharSet moves to Range. + /*public*/ CharRange[] getCharRanges() { + return set.toArray(new CharRange[set.size()]); + } + + //----------------------------------------------------------------------- + /** + *

Does the {@code CharSet} contain the specified + * character {@code ch}.

+ * + * @param ch the character to check for + * @return {@code true} if the set contains the characters + */ + public boolean contains(final char ch) { + for (final CharRange range : set) { + if (range.contains(ch)) { + return true; + } + } + return false; + } + + // Basics + //----------------------------------------------------------------------- + /** + *

Compares two {@code CharSet} objects, returning true if they represent + * exactly the same set of characters defined in the same way.

+ * + *

The two sets {@code abc} and {@code a-c} are not + * equal according to this method.

+ * + * @param obj the object to compare to + * @return true if equal + * @since 2.0 + */ + @Override + public boolean equals(final Object obj) { + if (obj == this) { + return true; + } + if (obj instanceof CharSet == false) { + return false; + } + final CharSet other = (CharSet) obj; + return set.equals(other.set); + } + + /** + *

Gets a hash code compatible with the equals method.

+ * + * @return a suitable hash code + * @since 2.0 + */ + @Override + public int hashCode() { + return 89 + set.hashCode(); + } + + /** + *

Gets a string representation of the set.

+ * + * @return string representation of the set + */ + @Override + public String toString() { + return set.toString(); + } + +} diff --git a/Java/commons-lang-CharSet_191/metadata.json b/Java/commons-lang-CharSet_191/metadata.json new file mode 100644 index 000000000..d5cb1ef68 --- /dev/null +++ b/Java/commons-lang-CharSet_191/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharSet_191", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/CharSet.java", + "line": 200, + "npe_method": "add", + "deref_field": "str", + "npe_class": "CharSet", + "repo": "commons-lang", + "bug_id": "CharSet_191" + } +} diff --git a/Java/commons-lang-CharSet_191/npe.json b/Java/commons-lang-CharSet_191/npe.json new file mode 100644 index 000000000..e432f69b2 --- /dev/null +++ b/Java/commons-lang-CharSet_191/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/CharSet.java", + "line": 200, + "npe_method": "add", + "deref_field": "str", + "npe_class": "CharSet" +} \ No newline at end of file diff --git a/Java/commons-lang-CharUtils_131/Dockerfile b/Java/commons-lang-CharUtils_131/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharUtils_131/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharUtils_131/buggy.java b/Java/commons-lang-CharUtils_131/buggy.java new file mode 100644 index 000000000..bed6cfb0c --- /dev/null +++ b/Java/commons-lang-CharUtils_131/buggy.java @@ -0,0 +1,568 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +/** + *

Operations on char primitives and Character objects.

+ * + *

This class tries to handle {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

+ * + *

#ThreadSafe#

+ * @since 2.1 + */ +public class CharUtils { + + private static final String[] CHAR_STRING_ARRAY = new String[128]; + + private static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + /** + * {@code \u000a} linefeed LF ('\n'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char LF = '\n'; + + /** + * {@code \u000d} carriage return CR ('\r'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char CR = '\r'; + + + static { + for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) { + CHAR_STRING_ARRAY[c] = String.valueOf(c); + } + } + + /** + *

{@code CharUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code CharUtils.toString('c');}.

+ * + *

This constructor is public to permit tools that require a JavaBean instance + * to operate.

+ */ + public CharUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to a Character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(' ')  = ' '
+     *   CharUtils.toCharacterObject('A')  = 'A'
+     * 
+ * + * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127. + * @param ch the character to convert + * @return a Character of the specified character + */ + @Deprecated + public static Character toCharacterObject(final char ch) { + return Character.valueOf(ch); + } + + /** + *

Converts the String to a Character using the first character, returning + * null for empty Strings.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(null) = null
+     *   CharUtils.toCharacterObject("")   = null
+     *   CharUtils.toCharacterObject("A")  = 'A'
+     *   CharUtils.toCharacterObject("BA") = 'B'
+     * 
+ * + * @param str the character to convert + * @return the Character value of the first letter of the String + */ + public static Character toCharacterObject(final String str) { + if (StringUtils.isEmpty(str)) { + return null; + } + return Character.valueOf(str.charAt(0)); + } + + //----------------------------------------------------------------------- + /** + *

Converts the Character to a char throwing an exception for {@code null}.

+ * + *
+     *   CharUtils.toChar(' ')  = ' '
+     *   CharUtils.toChar('A')  = 'A'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the char value of the Character + * @throws IllegalArgumentException if the Character is null + */ +// ----------------------------------------------------------------------- +/** + *

Converts the Character to a char throwing an exception for {@code null}.

+ * + *
+ * CharUtils.toChar(' ')  = ' '
+ * CharUtils.toChar('A')  = 'A'
+ * CharUtils.toChar(null) throws IllegalArgumentException
+ * 
+ * + * @param ch + * the character to convert + * @return the char value of the Character + * @throws IllegalArgumentException + * if the Character is null + */ +public static char toChar(final java.lang.Character ch) { + { + return /* NPEX_NULL_EXP */ + ch.charValue(); + } +} + + /** + *

Converts the Character to a char handling {@code null}.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar(' ', 'X')  = ' '
+     *   CharUtils.toChar('A', 'X')  = 'A'
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the Character or the default if null + */ + public static char toChar(final Character ch, final char defaultValue) { + if (ch == null) { + return defaultValue; + } + return ch.charValue(); + } + + //----------------------------------------------------------------------- + /** + *

Converts the String to a char using the first character, throwing + * an exception on empty Strings.

+ * + *
+     *   CharUtils.toChar("A")  = 'A'
+     *   CharUtils.toChar("BA") = 'B'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     *   CharUtils.toChar("")   throws IllegalArgumentException
+     * 
+ * + * @param str the character to convert + * @return the char value of the first letter of the String + * @throws IllegalArgumentException if the String is empty + */ + public static char toChar(final String str) { + if (StringUtils.isEmpty(str)) { + throw new IllegalArgumentException("The String must not be empty"); + } + return str.charAt(0); + } + + /** + *

Converts the String to a char using the first character, defaulting + * the value on empty Strings.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar("", 'X')   = 'X'
+     *   CharUtils.toChar("A", 'X')  = 'A'
+     *   CharUtils.toChar("BA", 'X') = 'B'
+     * 
+ * + * @param str the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the first letter of the String or the default if null + */ + public static char toChar(final String str, final char defaultValue) { + if (StringUtils.isEmpty(str)) { + return defaultValue; + } + return str.charAt(0); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the int value of the character + * @throws IllegalArgumentException if the character is not ASCII numeric + */ + public static int toIntValue(final char ch) { + if (isAsciiNumeric(ch) == false) { + throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'"); + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final char ch, final int defaultValue) { + if (isAsciiNumeric(ch) == false) { + return defaultValue; + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue(null) throws IllegalArgumentException
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert, not null + * @return the int value of the character + * @throws IllegalArgumentException if the Character is not ASCII numeric or is null + */ + public static int toIntValue(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The character must not be null"); + } + return toIntValue(ch.charValue()); + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue(null, -1) = -1
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final Character ch, final int defaultValue) { + if (ch == null) { + return defaultValue; + } + return toIntValue(ch.charValue(), defaultValue); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final char ch) { + if (ch < 128) { + return CHAR_STRING_ARRAY[ch]; + } + return new String(new char[] {ch}); + } + + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.toString(null) = null
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final Character ch) { + if (ch == null) { + return null; + } + return toString(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *
+     *   CharUtils.unicodeEscaped(' ') = "\u0020"
+     *   CharUtils.unicodeEscaped('A') = "\u0041"
+     * 
+ * + * @param ch the character to convert + * @return the escaped Unicode string + */ + public static String unicodeEscaped(final char ch) { + StringBuilder sb = new StringBuilder(6); + sb.append("\\u"); + sb.append(HEX_DIGITS[(ch >> 12) & 15]); + sb.append(HEX_DIGITS[(ch >> 8) & 15]); + sb.append(HEX_DIGITS[(ch >> 4) & 15]); + sb.append(HEX_DIGITS[(ch) & 15]); + return sb.toString(); + } + + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.unicodeEscaped(null) = null
+     *   CharUtils.unicodeEscaped(' ')  = "\u0020"
+     *   CharUtils.unicodeEscaped('A')  = "\u0041"
+     * 
+ * + * @param ch the character to convert, may be null + * @return the escaped Unicode string, null if null input + */ + public static String unicodeEscaped(final Character ch) { + if (ch == null) { + return null; + } + return unicodeEscaped(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

Checks whether the character is ASCII 7 bit.

+ * + *
+     *   CharUtils.isAscii('a')  = true
+     *   CharUtils.isAscii('A')  = true
+     *   CharUtils.isAscii('3')  = true
+     *   CharUtils.isAscii('-')  = true
+     *   CharUtils.isAscii('\n') = true
+     *   CharUtils.isAscii('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 128 + */ + public static boolean isAscii(final char ch) { + return ch < 128; + } + + /** + *

Checks whether the character is ASCII 7 bit printable.

+ * + *
+     *   CharUtils.isAsciiPrintable('a')  = true
+     *   CharUtils.isAsciiPrintable('A')  = true
+     *   CharUtils.isAsciiPrintable('3')  = true
+     *   CharUtils.isAsciiPrintable('-')  = true
+     *   CharUtils.isAsciiPrintable('\n') = false
+     *   CharUtils.isAsciiPrintable('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 32 and 126 inclusive + */ + public static boolean isAsciiPrintable(final char ch) { + return ch >= 32 && ch < 127; + } + + /** + *

Checks whether the character is ASCII 7 bit control.

+ * + *
+     *   CharUtils.isAsciiControl('a')  = false
+     *   CharUtils.isAsciiControl('A')  = false
+     *   CharUtils.isAsciiControl('3')  = false
+     *   CharUtils.isAsciiControl('-')  = false
+     *   CharUtils.isAsciiControl('\n') = true
+     *   CharUtils.isAsciiControl('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 32 or equals 127 + */ + public static boolean isAsciiControl(final char ch) { + return ch < 32 || ch == 127; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic.

+ * + *
+     *   CharUtils.isAsciiAlpha('a')  = true
+     *   CharUtils.isAsciiAlpha('A')  = true
+     *   CharUtils.isAsciiAlpha('3')  = false
+     *   CharUtils.isAsciiAlpha('-')  = false
+     *   CharUtils.isAsciiAlpha('\n') = false
+     *   CharUtils.isAsciiAlpha('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlpha(final char ch) { + return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch); + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic upper case.

+ * + *
+     *   CharUtils.isAsciiAlphaUpper('a')  = false
+     *   CharUtils.isAsciiAlphaUpper('A')  = true
+     *   CharUtils.isAsciiAlphaUpper('3')  = false
+     *   CharUtils.isAsciiAlphaUpper('-')  = false
+     *   CharUtils.isAsciiAlphaUpper('\n') = false
+     *   CharUtils.isAsciiAlphaUpper('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 inclusive + */ + public static boolean isAsciiAlphaUpper(final char ch) { + return ch >= 'A' && ch <= 'Z'; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic lower case.

+ * + *
+     *   CharUtils.isAsciiAlphaLower('a')  = true
+     *   CharUtils.isAsciiAlphaLower('A')  = false
+     *   CharUtils.isAsciiAlphaLower('3')  = false
+     *   CharUtils.isAsciiAlphaLower('-')  = false
+     *   CharUtils.isAsciiAlphaLower('\n') = false
+     *   CharUtils.isAsciiAlphaLower('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 97 and 122 inclusive + */ + public static boolean isAsciiAlphaLower(final char ch) { + return ch >= 'a' && ch <= 'z'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiNumeric('a')  = false
+     *   CharUtils.isAsciiNumeric('A')  = false
+     *   CharUtils.isAsciiNumeric('3')  = true
+     *   CharUtils.isAsciiNumeric('-')  = false
+     *   CharUtils.isAsciiNumeric('\n') = false
+     *   CharUtils.isAsciiNumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 inclusive + */ + public static boolean isAsciiNumeric(final char ch) { + return ch >= '0' && ch <= '9'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiAlphanumeric('a')  = true
+     *   CharUtils.isAsciiAlphanumeric('A')  = true
+     *   CharUtils.isAsciiAlphanumeric('3')  = true
+     *   CharUtils.isAsciiAlphanumeric('-')  = false
+     *   CharUtils.isAsciiAlphanumeric('\n') = false
+     *   CharUtils.isAsciiAlphanumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlphanumeric(final char ch) { + return isAsciiAlpha(ch) || isAsciiNumeric(ch); + } + + /** + *

Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code char} to compare + * @param y the second {@code char} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(char x, char y) { + return x-y; + } +} diff --git a/Java/commons-lang-CharUtils_131/metadata.json b/Java/commons-lang-CharUtils_131/metadata.json new file mode 100644 index 000000000..8e9d9f7df --- /dev/null +++ b/Java/commons-lang-CharUtils_131/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharUtils_131", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 149, + "npe_method": "toChar", + "deref_field": "ch", + "npe_class": "CharUtils", + "repo": "commons-lang", + "bug_id": "CharUtils_131" + } +} diff --git a/Java/commons-lang-CharUtils_131/npe.json b/Java/commons-lang-CharUtils_131/npe.json new file mode 100644 index 000000000..e9e0c01f8 --- /dev/null +++ b/Java/commons-lang-CharUtils_131/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 149, + "npe_method": "toChar", + "deref_field": "ch", + "npe_class": "CharUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-CharUtils_151/Dockerfile b/Java/commons-lang-CharUtils_151/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharUtils_151/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharUtils_151/buggy.java b/Java/commons-lang-CharUtils_151/buggy.java new file mode 100644 index 000000000..3bc6b1928 --- /dev/null +++ b/Java/commons-lang-CharUtils_151/buggy.java @@ -0,0 +1,567 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +/** + *

Operations on char primitives and Character objects.

+ * + *

This class tries to handle {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

+ * + *

#ThreadSafe#

+ * @since 2.1 + */ +public class CharUtils { + + private static final String[] CHAR_STRING_ARRAY = new String[128]; + + private static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + /** + * {@code \u000a} linefeed LF ('\n'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char LF = '\n'; + + /** + * {@code \u000d} carriage return CR ('\r'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char CR = '\r'; + + + static { + for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) { + CHAR_STRING_ARRAY[c] = String.valueOf(c); + } + } + + /** + *

{@code CharUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code CharUtils.toString('c');}.

+ * + *

This constructor is public to permit tools that require a JavaBean instance + * to operate.

+ */ + public CharUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to a Character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(' ')  = ' '
+     *   CharUtils.toCharacterObject('A')  = 'A'
+     * 
+ * + * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127. + * @param ch the character to convert + * @return a Character of the specified character + */ + @Deprecated + public static Character toCharacterObject(final char ch) { + return Character.valueOf(ch); + } + + /** + *

Converts the String to a Character using the first character, returning + * null for empty Strings.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(null) = null
+     *   CharUtils.toCharacterObject("")   = null
+     *   CharUtils.toCharacterObject("A")  = 'A'
+     *   CharUtils.toCharacterObject("BA") = 'B'
+     * 
+ * + * @param str the character to convert + * @return the Character value of the first letter of the String + */ + public static Character toCharacterObject(final String str) { + if (StringUtils.isEmpty(str)) { + return null; + } + return Character.valueOf(str.charAt(0)); + } + + //----------------------------------------------------------------------- + /** + *

Converts the Character to a char throwing an exception for {@code null}.

+ * + *
+     *   CharUtils.toChar(' ')  = ' '
+     *   CharUtils.toChar('A')  = 'A'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the char value of the Character + * @throws IllegalArgumentException if the Character is null + */ + public static char toChar(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The Character must not be null"); + } + return ch.charValue(); + } + + /** + *

Converts the Character to a char handling {@code null}.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar(' ', 'X')  = ' '
+     *   CharUtils.toChar('A', 'X')  = 'A'
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the Character or the default if null + */ +/** + *

Converts the Character to a char handling {@code null}.

+ * + *
+ * CharUtils.toChar(null, 'X') = 'X'
+ * CharUtils.toChar(' ', 'X')  = ' '
+ * CharUtils.toChar('A', 'X')  = 'A'
+ * 
+ * + * @param ch + * the character to convert + * @param defaultValue + * the value to use if the Character is null + * @return the char value of the Character or the default if null + */ +public static char toChar(final java.lang.Character ch, final char defaultValue) { + { + return /* NPEX_NULL_EXP */ + ch.charValue(); + } +} + + //----------------------------------------------------------------------- + /** + *

Converts the String to a char using the first character, throwing + * an exception on empty Strings.

+ * + *
+     *   CharUtils.toChar("A")  = 'A'
+     *   CharUtils.toChar("BA") = 'B'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     *   CharUtils.toChar("")   throws IllegalArgumentException
+     * 
+ * + * @param str the character to convert + * @return the char value of the first letter of the String + * @throws IllegalArgumentException if the String is empty + */ + public static char toChar(final String str) { + if (StringUtils.isEmpty(str)) { + throw new IllegalArgumentException("The String must not be empty"); + } + return str.charAt(0); + } + + /** + *

Converts the String to a char using the first character, defaulting + * the value on empty Strings.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar("", 'X')   = 'X'
+     *   CharUtils.toChar("A", 'X')  = 'A'
+     *   CharUtils.toChar("BA", 'X') = 'B'
+     * 
+ * + * @param str the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the first letter of the String or the default if null + */ + public static char toChar(final String str, final char defaultValue) { + if (StringUtils.isEmpty(str)) { + return defaultValue; + } + return str.charAt(0); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the int value of the character + * @throws IllegalArgumentException if the character is not ASCII numeric + */ + public static int toIntValue(final char ch) { + if (isAsciiNumeric(ch) == false) { + throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'"); + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final char ch, final int defaultValue) { + if (isAsciiNumeric(ch) == false) { + return defaultValue; + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue(null) throws IllegalArgumentException
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert, not null + * @return the int value of the character + * @throws IllegalArgumentException if the Character is not ASCII numeric or is null + */ + public static int toIntValue(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The character must not be null"); + } + return toIntValue(ch.charValue()); + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue(null, -1) = -1
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final Character ch, final int defaultValue) { + if (ch == null) { + return defaultValue; + } + return toIntValue(ch.charValue(), defaultValue); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final char ch) { + if (ch < 128) { + return CHAR_STRING_ARRAY[ch]; + } + return new String(new char[] {ch}); + } + + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.toString(null) = null
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final Character ch) { + if (ch == null) { + return null; + } + return toString(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *
+     *   CharUtils.unicodeEscaped(' ') = "\u0020"
+     *   CharUtils.unicodeEscaped('A') = "\u0041"
+     * 
+ * + * @param ch the character to convert + * @return the escaped Unicode string + */ + public static String unicodeEscaped(final char ch) { + StringBuilder sb = new StringBuilder(6); + sb.append("\\u"); + sb.append(HEX_DIGITS[(ch >> 12) & 15]); + sb.append(HEX_DIGITS[(ch >> 8) & 15]); + sb.append(HEX_DIGITS[(ch >> 4) & 15]); + sb.append(HEX_DIGITS[(ch) & 15]); + return sb.toString(); + } + + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.unicodeEscaped(null) = null
+     *   CharUtils.unicodeEscaped(' ')  = "\u0020"
+     *   CharUtils.unicodeEscaped('A')  = "\u0041"
+     * 
+ * + * @param ch the character to convert, may be null + * @return the escaped Unicode string, null if null input + */ + public static String unicodeEscaped(final Character ch) { + if (ch == null) { + return null; + } + return unicodeEscaped(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

Checks whether the character is ASCII 7 bit.

+ * + *
+     *   CharUtils.isAscii('a')  = true
+     *   CharUtils.isAscii('A')  = true
+     *   CharUtils.isAscii('3')  = true
+     *   CharUtils.isAscii('-')  = true
+     *   CharUtils.isAscii('\n') = true
+     *   CharUtils.isAscii('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 128 + */ + public static boolean isAscii(final char ch) { + return ch < 128; + } + + /** + *

Checks whether the character is ASCII 7 bit printable.

+ * + *
+     *   CharUtils.isAsciiPrintable('a')  = true
+     *   CharUtils.isAsciiPrintable('A')  = true
+     *   CharUtils.isAsciiPrintable('3')  = true
+     *   CharUtils.isAsciiPrintable('-')  = true
+     *   CharUtils.isAsciiPrintable('\n') = false
+     *   CharUtils.isAsciiPrintable('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 32 and 126 inclusive + */ + public static boolean isAsciiPrintable(final char ch) { + return ch >= 32 && ch < 127; + } + + /** + *

Checks whether the character is ASCII 7 bit control.

+ * + *
+     *   CharUtils.isAsciiControl('a')  = false
+     *   CharUtils.isAsciiControl('A')  = false
+     *   CharUtils.isAsciiControl('3')  = false
+     *   CharUtils.isAsciiControl('-')  = false
+     *   CharUtils.isAsciiControl('\n') = true
+     *   CharUtils.isAsciiControl('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 32 or equals 127 + */ + public static boolean isAsciiControl(final char ch) { + return ch < 32 || ch == 127; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic.

+ * + *
+     *   CharUtils.isAsciiAlpha('a')  = true
+     *   CharUtils.isAsciiAlpha('A')  = true
+     *   CharUtils.isAsciiAlpha('3')  = false
+     *   CharUtils.isAsciiAlpha('-')  = false
+     *   CharUtils.isAsciiAlpha('\n') = false
+     *   CharUtils.isAsciiAlpha('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlpha(final char ch) { + return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch); + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic upper case.

+ * + *
+     *   CharUtils.isAsciiAlphaUpper('a')  = false
+     *   CharUtils.isAsciiAlphaUpper('A')  = true
+     *   CharUtils.isAsciiAlphaUpper('3')  = false
+     *   CharUtils.isAsciiAlphaUpper('-')  = false
+     *   CharUtils.isAsciiAlphaUpper('\n') = false
+     *   CharUtils.isAsciiAlphaUpper('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 inclusive + */ + public static boolean isAsciiAlphaUpper(final char ch) { + return ch >= 'A' && ch <= 'Z'; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic lower case.

+ * + *
+     *   CharUtils.isAsciiAlphaLower('a')  = true
+     *   CharUtils.isAsciiAlphaLower('A')  = false
+     *   CharUtils.isAsciiAlphaLower('3')  = false
+     *   CharUtils.isAsciiAlphaLower('-')  = false
+     *   CharUtils.isAsciiAlphaLower('\n') = false
+     *   CharUtils.isAsciiAlphaLower('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 97 and 122 inclusive + */ + public static boolean isAsciiAlphaLower(final char ch) { + return ch >= 'a' && ch <= 'z'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiNumeric('a')  = false
+     *   CharUtils.isAsciiNumeric('A')  = false
+     *   CharUtils.isAsciiNumeric('3')  = true
+     *   CharUtils.isAsciiNumeric('-')  = false
+     *   CharUtils.isAsciiNumeric('\n') = false
+     *   CharUtils.isAsciiNumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 inclusive + */ + public static boolean isAsciiNumeric(final char ch) { + return ch >= '0' && ch <= '9'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiAlphanumeric('a')  = true
+     *   CharUtils.isAsciiAlphanumeric('A')  = true
+     *   CharUtils.isAsciiAlphanumeric('3')  = true
+     *   CharUtils.isAsciiAlphanumeric('-')  = false
+     *   CharUtils.isAsciiAlphanumeric('\n') = false
+     *   CharUtils.isAsciiAlphanumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlphanumeric(final char ch) { + return isAsciiAlpha(ch) || isAsciiNumeric(ch); + } + + /** + *

Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code char} to compare + * @param y the second {@code char} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(char x, char y) { + return x-y; + } +} diff --git a/Java/commons-lang-CharUtils_151/metadata.json b/Java/commons-lang-CharUtils_151/metadata.json new file mode 100644 index 000000000..61ecf8bd0 --- /dev/null +++ b/Java/commons-lang-CharUtils_151/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharUtils_151", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 168, + "npe_method": "toChar", + "deref_field": "ch", + "npe_class": "CharUtils", + "repo": "commons-lang", + "bug_id": "CharUtils_151" + } +} diff --git a/Java/commons-lang-CharUtils_151/npe.json b/Java/commons-lang-CharUtils_151/npe.json new file mode 100644 index 000000000..efeb4ffe0 --- /dev/null +++ b/Java/commons-lang-CharUtils_151/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 168, + "npe_method": "toChar", + "deref_field": "ch", + "npe_class": "CharUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-CharUtils_264/Dockerfile b/Java/commons-lang-CharUtils_264/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharUtils_264/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharUtils_264/buggy.java b/Java/commons-lang-CharUtils_264/buggy.java new file mode 100644 index 000000000..2fff9bd7d --- /dev/null +++ b/Java/commons-lang-CharUtils_264/buggy.java @@ -0,0 +1,570 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +/** + *

Operations on char primitives and Character objects.

+ * + *

This class tries to handle {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

+ * + *

#ThreadSafe#

+ * @since 2.1 + */ +public class CharUtils { + + private static final String[] CHAR_STRING_ARRAY = new String[128]; + + private static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + /** + * {@code \u000a} linefeed LF ('\n'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char LF = '\n'; + + /** + * {@code \u000d} carriage return CR ('\r'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char CR = '\r'; + + + static { + for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) { + CHAR_STRING_ARRAY[c] = String.valueOf(c); + } + } + + /** + *

{@code CharUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code CharUtils.toString('c');}.

+ * + *

This constructor is public to permit tools that require a JavaBean instance + * to operate.

+ */ + public CharUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to a Character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(' ')  = ' '
+     *   CharUtils.toCharacterObject('A')  = 'A'
+     * 
+ * + * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127. + * @param ch the character to convert + * @return a Character of the specified character + */ + @Deprecated + public static Character toCharacterObject(final char ch) { + return Character.valueOf(ch); + } + + /** + *

Converts the String to a Character using the first character, returning + * null for empty Strings.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(null) = null
+     *   CharUtils.toCharacterObject("")   = null
+     *   CharUtils.toCharacterObject("A")  = 'A'
+     *   CharUtils.toCharacterObject("BA") = 'B'
+     * 
+ * + * @param str the character to convert + * @return the Character value of the first letter of the String + */ + public static Character toCharacterObject(final String str) { + if (StringUtils.isEmpty(str)) { + return null; + } + return Character.valueOf(str.charAt(0)); + } + + //----------------------------------------------------------------------- + /** + *

Converts the Character to a char throwing an exception for {@code null}.

+ * + *
+     *   CharUtils.toChar(' ')  = ' '
+     *   CharUtils.toChar('A')  = 'A'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the char value of the Character + * @throws IllegalArgumentException if the Character is null + */ + public static char toChar(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The Character must not be null"); + } + return ch.charValue(); + } + + /** + *

Converts the Character to a char handling {@code null}.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar(' ', 'X')  = ' '
+     *   CharUtils.toChar('A', 'X')  = 'A'
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the Character or the default if null + */ + public static char toChar(final Character ch, final char defaultValue) { + if (ch == null) { + return defaultValue; + } + return ch.charValue(); + } + + //----------------------------------------------------------------------- + /** + *

Converts the String to a char using the first character, throwing + * an exception on empty Strings.

+ * + *
+     *   CharUtils.toChar("A")  = 'A'
+     *   CharUtils.toChar("BA") = 'B'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     *   CharUtils.toChar("")   throws IllegalArgumentException
+     * 
+ * + * @param str the character to convert + * @return the char value of the first letter of the String + * @throws IllegalArgumentException if the String is empty + */ + public static char toChar(final String str) { + if (StringUtils.isEmpty(str)) { + throw new IllegalArgumentException("The String must not be empty"); + } + return str.charAt(0); + } + + /** + *

Converts the String to a char using the first character, defaulting + * the value on empty Strings.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar("", 'X')   = 'X'
+     *   CharUtils.toChar("A", 'X')  = 'A'
+     *   CharUtils.toChar("BA", 'X') = 'B'
+     * 
+ * + * @param str the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the first letter of the String or the default if null + */ + public static char toChar(final String str, final char defaultValue) { + if (StringUtils.isEmpty(str)) { + return defaultValue; + } + return str.charAt(0); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the int value of the character + * @throws IllegalArgumentException if the character is not ASCII numeric + */ + public static int toIntValue(final char ch) { + if (isAsciiNumeric(ch) == false) { + throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'"); + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final char ch, final int defaultValue) { + if (isAsciiNumeric(ch) == false) { + return defaultValue; + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue(null) throws IllegalArgumentException
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert, not null + * @return the int value of the character + * @throws IllegalArgumentException if the Character is not ASCII numeric or is null + */ +/** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+ * CharUtils.toIntValue('3')  = 3
+ * CharUtils.toIntValue(null) throws IllegalArgumentException
+ * CharUtils.toIntValue('A')  throws IllegalArgumentException
+ * 
+ * + * @param ch + * the character to convert, not null + * @return the int value of the character + * @throws IllegalArgumentException + * if the Character is not ASCII numeric or is null + */ +public static int toIntValue(final java.lang.Character ch) { + { + return org.apache.commons.lang3.CharUtils.toIntValue(/* NPEX_NULL_EXP */ + ch.charValue()); + } +} + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue(null, -1) = -1
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final Character ch, final int defaultValue) { + if (ch == null) { + return defaultValue; + } + return toIntValue(ch.charValue(), defaultValue); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final char ch) { + if (ch < 128) { + return CHAR_STRING_ARRAY[ch]; + } + return new String(new char[] {ch}); + } + + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.toString(null) = null
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final Character ch) { + if (ch == null) { + return null; + } + return toString(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *
+     *   CharUtils.unicodeEscaped(' ') = "\u0020"
+     *   CharUtils.unicodeEscaped('A') = "\u0041"
+     * 
+ * + * @param ch the character to convert + * @return the escaped Unicode string + */ + public static String unicodeEscaped(final char ch) { + StringBuilder sb = new StringBuilder(6); + sb.append("\\u"); + sb.append(HEX_DIGITS[(ch >> 12) & 15]); + sb.append(HEX_DIGITS[(ch >> 8) & 15]); + sb.append(HEX_DIGITS[(ch >> 4) & 15]); + sb.append(HEX_DIGITS[(ch) & 15]); + return sb.toString(); + } + + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.unicodeEscaped(null) = null
+     *   CharUtils.unicodeEscaped(' ')  = "\u0020"
+     *   CharUtils.unicodeEscaped('A')  = "\u0041"
+     * 
+ * + * @param ch the character to convert, may be null + * @return the escaped Unicode string, null if null input + */ + public static String unicodeEscaped(final Character ch) { + if (ch == null) { + return null; + } + return unicodeEscaped(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

Checks whether the character is ASCII 7 bit.

+ * + *
+     *   CharUtils.isAscii('a')  = true
+     *   CharUtils.isAscii('A')  = true
+     *   CharUtils.isAscii('3')  = true
+     *   CharUtils.isAscii('-')  = true
+     *   CharUtils.isAscii('\n') = true
+     *   CharUtils.isAscii('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 128 + */ + public static boolean isAscii(final char ch) { + return ch < 128; + } + + /** + *

Checks whether the character is ASCII 7 bit printable.

+ * + *
+     *   CharUtils.isAsciiPrintable('a')  = true
+     *   CharUtils.isAsciiPrintable('A')  = true
+     *   CharUtils.isAsciiPrintable('3')  = true
+     *   CharUtils.isAsciiPrintable('-')  = true
+     *   CharUtils.isAsciiPrintable('\n') = false
+     *   CharUtils.isAsciiPrintable('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 32 and 126 inclusive + */ + public static boolean isAsciiPrintable(final char ch) { + return ch >= 32 && ch < 127; + } + + /** + *

Checks whether the character is ASCII 7 bit control.

+ * + *
+     *   CharUtils.isAsciiControl('a')  = false
+     *   CharUtils.isAsciiControl('A')  = false
+     *   CharUtils.isAsciiControl('3')  = false
+     *   CharUtils.isAsciiControl('-')  = false
+     *   CharUtils.isAsciiControl('\n') = true
+     *   CharUtils.isAsciiControl('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 32 or equals 127 + */ + public static boolean isAsciiControl(final char ch) { + return ch < 32 || ch == 127; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic.

+ * + *
+     *   CharUtils.isAsciiAlpha('a')  = true
+     *   CharUtils.isAsciiAlpha('A')  = true
+     *   CharUtils.isAsciiAlpha('3')  = false
+     *   CharUtils.isAsciiAlpha('-')  = false
+     *   CharUtils.isAsciiAlpha('\n') = false
+     *   CharUtils.isAsciiAlpha('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlpha(final char ch) { + return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch); + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic upper case.

+ * + *
+     *   CharUtils.isAsciiAlphaUpper('a')  = false
+     *   CharUtils.isAsciiAlphaUpper('A')  = true
+     *   CharUtils.isAsciiAlphaUpper('3')  = false
+     *   CharUtils.isAsciiAlphaUpper('-')  = false
+     *   CharUtils.isAsciiAlphaUpper('\n') = false
+     *   CharUtils.isAsciiAlphaUpper('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 inclusive + */ + public static boolean isAsciiAlphaUpper(final char ch) { + return ch >= 'A' && ch <= 'Z'; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic lower case.

+ * + *
+     *   CharUtils.isAsciiAlphaLower('a')  = true
+     *   CharUtils.isAsciiAlphaLower('A')  = false
+     *   CharUtils.isAsciiAlphaLower('3')  = false
+     *   CharUtils.isAsciiAlphaLower('-')  = false
+     *   CharUtils.isAsciiAlphaLower('\n') = false
+     *   CharUtils.isAsciiAlphaLower('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 97 and 122 inclusive + */ + public static boolean isAsciiAlphaLower(final char ch) { + return ch >= 'a' && ch <= 'z'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiNumeric('a')  = false
+     *   CharUtils.isAsciiNumeric('A')  = false
+     *   CharUtils.isAsciiNumeric('3')  = true
+     *   CharUtils.isAsciiNumeric('-')  = false
+     *   CharUtils.isAsciiNumeric('\n') = false
+     *   CharUtils.isAsciiNumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 inclusive + */ + public static boolean isAsciiNumeric(final char ch) { + return ch >= '0' && ch <= '9'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiAlphanumeric('a')  = true
+     *   CharUtils.isAsciiAlphanumeric('A')  = true
+     *   CharUtils.isAsciiAlphanumeric('3')  = true
+     *   CharUtils.isAsciiAlphanumeric('-')  = false
+     *   CharUtils.isAsciiAlphanumeric('\n') = false
+     *   CharUtils.isAsciiAlphanumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlphanumeric(final char ch) { + return isAsciiAlpha(ch) || isAsciiNumeric(ch); + } + + /** + *

Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code char} to compare + * @param y the second {@code char} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(char x, char y) { + return x-y; + } +} diff --git a/Java/commons-lang-CharUtils_264/metadata.json b/Java/commons-lang-CharUtils_264/metadata.json new file mode 100644 index 000000000..39fbc1d7c --- /dev/null +++ b/Java/commons-lang-CharUtils_264/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharUtils_264", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 284, + "npe_method": "toIntValue", + "deref_field": "ch", + "npe_class": "CharUtils", + "repo": "commons-lang", + "bug_id": "CharUtils_264" + } +} diff --git a/Java/commons-lang-CharUtils_264/npe.json b/Java/commons-lang-CharUtils_264/npe.json new file mode 100644 index 000000000..335d9ed77 --- /dev/null +++ b/Java/commons-lang-CharUtils_264/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 284, + "npe_method": "toIntValue", + "deref_field": "ch", + "npe_class": "CharUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-CharUtils_287/Dockerfile b/Java/commons-lang-CharUtils_287/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharUtils_287/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharUtils_287/buggy.java b/Java/commons-lang-CharUtils_287/buggy.java new file mode 100644 index 000000000..5b1ed3384 --- /dev/null +++ b/Java/commons-lang-CharUtils_287/buggy.java @@ -0,0 +1,570 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +/** + *

Operations on char primitives and Character objects.

+ * + *

This class tries to handle {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

+ * + *

#ThreadSafe#

+ * @since 2.1 + */ +public class CharUtils { + + private static final String[] CHAR_STRING_ARRAY = new String[128]; + + private static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + /** + * {@code \u000a} linefeed LF ('\n'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char LF = '\n'; + + /** + * {@code \u000d} carriage return CR ('\r'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char CR = '\r'; + + + static { + for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) { + CHAR_STRING_ARRAY[c] = String.valueOf(c); + } + } + + /** + *

{@code CharUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code CharUtils.toString('c');}.

+ * + *

This constructor is public to permit tools that require a JavaBean instance + * to operate.

+ */ + public CharUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to a Character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(' ')  = ' '
+     *   CharUtils.toCharacterObject('A')  = 'A'
+     * 
+ * + * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127. + * @param ch the character to convert + * @return a Character of the specified character + */ + @Deprecated + public static Character toCharacterObject(final char ch) { + return Character.valueOf(ch); + } + + /** + *

Converts the String to a Character using the first character, returning + * null for empty Strings.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(null) = null
+     *   CharUtils.toCharacterObject("")   = null
+     *   CharUtils.toCharacterObject("A")  = 'A'
+     *   CharUtils.toCharacterObject("BA") = 'B'
+     * 
+ * + * @param str the character to convert + * @return the Character value of the first letter of the String + */ + public static Character toCharacterObject(final String str) { + if (StringUtils.isEmpty(str)) { + return null; + } + return Character.valueOf(str.charAt(0)); + } + + //----------------------------------------------------------------------- + /** + *

Converts the Character to a char throwing an exception for {@code null}.

+ * + *
+     *   CharUtils.toChar(' ')  = ' '
+     *   CharUtils.toChar('A')  = 'A'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the char value of the Character + * @throws IllegalArgumentException if the Character is null + */ + public static char toChar(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The Character must not be null"); + } + return ch.charValue(); + } + + /** + *

Converts the Character to a char handling {@code null}.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar(' ', 'X')  = ' '
+     *   CharUtils.toChar('A', 'X')  = 'A'
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the Character or the default if null + */ + public static char toChar(final Character ch, final char defaultValue) { + if (ch == null) { + return defaultValue; + } + return ch.charValue(); + } + + //----------------------------------------------------------------------- + /** + *

Converts the String to a char using the first character, throwing + * an exception on empty Strings.

+ * + *
+     *   CharUtils.toChar("A")  = 'A'
+     *   CharUtils.toChar("BA") = 'B'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     *   CharUtils.toChar("")   throws IllegalArgumentException
+     * 
+ * + * @param str the character to convert + * @return the char value of the first letter of the String + * @throws IllegalArgumentException if the String is empty + */ + public static char toChar(final String str) { + if (StringUtils.isEmpty(str)) { + throw new IllegalArgumentException("The String must not be empty"); + } + return str.charAt(0); + } + + /** + *

Converts the String to a char using the first character, defaulting + * the value on empty Strings.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar("", 'X')   = 'X'
+     *   CharUtils.toChar("A", 'X')  = 'A'
+     *   CharUtils.toChar("BA", 'X') = 'B'
+     * 
+ * + * @param str the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the first letter of the String or the default if null + */ + public static char toChar(final String str, final char defaultValue) { + if (StringUtils.isEmpty(str)) { + return defaultValue; + } + return str.charAt(0); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the int value of the character + * @throws IllegalArgumentException if the character is not ASCII numeric + */ + public static int toIntValue(final char ch) { + if (isAsciiNumeric(ch) == false) { + throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'"); + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final char ch, final int defaultValue) { + if (isAsciiNumeric(ch) == false) { + return defaultValue; + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue(null) throws IllegalArgumentException
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert, not null + * @return the int value of the character + * @throws IllegalArgumentException if the Character is not ASCII numeric or is null + */ + public static int toIntValue(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The character must not be null"); + } + return toIntValue(ch.charValue()); + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue(null, -1) = -1
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ +/** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+ * CharUtils.toIntValue(null, -1) = -1
+ * CharUtils.toIntValue('3', -1)  = 3
+ * CharUtils.toIntValue('A', -1)  = -1
+ * 
+ * + * @param ch + * the character to convert + * @param defaultValue + * the default value to use if the character is not numeric + * @return the int value of the character + */ +public static int toIntValue(final java.lang.Character ch, final int defaultValue) { + { + return org.apache.commons.lang3.CharUtils.toIntValue(/* NPEX_NULL_EXP */ + ch.charValue(), defaultValue); + } +} + + //----------------------------------------------------------------------- + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final char ch) { + if (ch < 128) { + return CHAR_STRING_ARRAY[ch]; + } + return new String(new char[] {ch}); + } + + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.toString(null) = null
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final Character ch) { + if (ch == null) { + return null; + } + return toString(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *
+     *   CharUtils.unicodeEscaped(' ') = "\u0020"
+     *   CharUtils.unicodeEscaped('A') = "\u0041"
+     * 
+ * + * @param ch the character to convert + * @return the escaped Unicode string + */ + public static String unicodeEscaped(final char ch) { + StringBuilder sb = new StringBuilder(6); + sb.append("\\u"); + sb.append(HEX_DIGITS[(ch >> 12) & 15]); + sb.append(HEX_DIGITS[(ch >> 8) & 15]); + sb.append(HEX_DIGITS[(ch >> 4) & 15]); + sb.append(HEX_DIGITS[(ch) & 15]); + return sb.toString(); + } + + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.unicodeEscaped(null) = null
+     *   CharUtils.unicodeEscaped(' ')  = "\u0020"
+     *   CharUtils.unicodeEscaped('A')  = "\u0041"
+     * 
+ * + * @param ch the character to convert, may be null + * @return the escaped Unicode string, null if null input + */ + public static String unicodeEscaped(final Character ch) { + if (ch == null) { + return null; + } + return unicodeEscaped(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

Checks whether the character is ASCII 7 bit.

+ * + *
+     *   CharUtils.isAscii('a')  = true
+     *   CharUtils.isAscii('A')  = true
+     *   CharUtils.isAscii('3')  = true
+     *   CharUtils.isAscii('-')  = true
+     *   CharUtils.isAscii('\n') = true
+     *   CharUtils.isAscii('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 128 + */ + public static boolean isAscii(final char ch) { + return ch < 128; + } + + /** + *

Checks whether the character is ASCII 7 bit printable.

+ * + *
+     *   CharUtils.isAsciiPrintable('a')  = true
+     *   CharUtils.isAsciiPrintable('A')  = true
+     *   CharUtils.isAsciiPrintable('3')  = true
+     *   CharUtils.isAsciiPrintable('-')  = true
+     *   CharUtils.isAsciiPrintable('\n') = false
+     *   CharUtils.isAsciiPrintable('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 32 and 126 inclusive + */ + public static boolean isAsciiPrintable(final char ch) { + return ch >= 32 && ch < 127; + } + + /** + *

Checks whether the character is ASCII 7 bit control.

+ * + *
+     *   CharUtils.isAsciiControl('a')  = false
+     *   CharUtils.isAsciiControl('A')  = false
+     *   CharUtils.isAsciiControl('3')  = false
+     *   CharUtils.isAsciiControl('-')  = false
+     *   CharUtils.isAsciiControl('\n') = true
+     *   CharUtils.isAsciiControl('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 32 or equals 127 + */ + public static boolean isAsciiControl(final char ch) { + return ch < 32 || ch == 127; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic.

+ * + *
+     *   CharUtils.isAsciiAlpha('a')  = true
+     *   CharUtils.isAsciiAlpha('A')  = true
+     *   CharUtils.isAsciiAlpha('3')  = false
+     *   CharUtils.isAsciiAlpha('-')  = false
+     *   CharUtils.isAsciiAlpha('\n') = false
+     *   CharUtils.isAsciiAlpha('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlpha(final char ch) { + return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch); + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic upper case.

+ * + *
+     *   CharUtils.isAsciiAlphaUpper('a')  = false
+     *   CharUtils.isAsciiAlphaUpper('A')  = true
+     *   CharUtils.isAsciiAlphaUpper('3')  = false
+     *   CharUtils.isAsciiAlphaUpper('-')  = false
+     *   CharUtils.isAsciiAlphaUpper('\n') = false
+     *   CharUtils.isAsciiAlphaUpper('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 inclusive + */ + public static boolean isAsciiAlphaUpper(final char ch) { + return ch >= 'A' && ch <= 'Z'; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic lower case.

+ * + *
+     *   CharUtils.isAsciiAlphaLower('a')  = true
+     *   CharUtils.isAsciiAlphaLower('A')  = false
+     *   CharUtils.isAsciiAlphaLower('3')  = false
+     *   CharUtils.isAsciiAlphaLower('-')  = false
+     *   CharUtils.isAsciiAlphaLower('\n') = false
+     *   CharUtils.isAsciiAlphaLower('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 97 and 122 inclusive + */ + public static boolean isAsciiAlphaLower(final char ch) { + return ch >= 'a' && ch <= 'z'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiNumeric('a')  = false
+     *   CharUtils.isAsciiNumeric('A')  = false
+     *   CharUtils.isAsciiNumeric('3')  = true
+     *   CharUtils.isAsciiNumeric('-')  = false
+     *   CharUtils.isAsciiNumeric('\n') = false
+     *   CharUtils.isAsciiNumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 inclusive + */ + public static boolean isAsciiNumeric(final char ch) { + return ch >= '0' && ch <= '9'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiAlphanumeric('a')  = true
+     *   CharUtils.isAsciiAlphanumeric('A')  = true
+     *   CharUtils.isAsciiAlphanumeric('3')  = true
+     *   CharUtils.isAsciiAlphanumeric('-')  = false
+     *   CharUtils.isAsciiAlphanumeric('\n') = false
+     *   CharUtils.isAsciiAlphanumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlphanumeric(final char ch) { + return isAsciiAlpha(ch) || isAsciiNumeric(ch); + } + + /** + *

Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code char} to compare + * @param y the second {@code char} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(char x, char y) { + return x-y; + } +} diff --git a/Java/commons-lang-CharUtils_287/metadata.json b/Java/commons-lang-CharUtils_287/metadata.json new file mode 100644 index 000000000..aaf6cc048 --- /dev/null +++ b/Java/commons-lang-CharUtils_287/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharUtils_287", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 307, + "npe_method": "toIntValue", + "deref_field": "ch", + "npe_class": "CharUtils", + "repo": "commons-lang", + "bug_id": "CharUtils_287" + } +} diff --git a/Java/commons-lang-CharUtils_287/npe.json b/Java/commons-lang-CharUtils_287/npe.json new file mode 100644 index 000000000..bd150cc24 --- /dev/null +++ b/Java/commons-lang-CharUtils_287/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 307, + "npe_method": "toIntValue", + "deref_field": "ch", + "npe_class": "CharUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-CharUtils_333/Dockerfile b/Java/commons-lang-CharUtils_333/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharUtils_333/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharUtils_333/buggy.java b/Java/commons-lang-CharUtils_333/buggy.java new file mode 100644 index 000000000..9b2e533fc --- /dev/null +++ b/Java/commons-lang-CharUtils_333/buggy.java @@ -0,0 +1,570 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +/** + *

Operations on char primitives and Character objects.

+ * + *

This class tries to handle {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

+ * + *

#ThreadSafe#

+ * @since 2.1 + */ +public class CharUtils { + + private static final String[] CHAR_STRING_ARRAY = new String[128]; + + private static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + /** + * {@code \u000a} linefeed LF ('\n'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char LF = '\n'; + + /** + * {@code \u000d} carriage return CR ('\r'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char CR = '\r'; + + + static { + for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) { + CHAR_STRING_ARRAY[c] = String.valueOf(c); + } + } + + /** + *

{@code CharUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code CharUtils.toString('c');}.

+ * + *

This constructor is public to permit tools that require a JavaBean instance + * to operate.

+ */ + public CharUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to a Character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(' ')  = ' '
+     *   CharUtils.toCharacterObject('A')  = 'A'
+     * 
+ * + * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127. + * @param ch the character to convert + * @return a Character of the specified character + */ + @Deprecated + public static Character toCharacterObject(final char ch) { + return Character.valueOf(ch); + } + + /** + *

Converts the String to a Character using the first character, returning + * null for empty Strings.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(null) = null
+     *   CharUtils.toCharacterObject("")   = null
+     *   CharUtils.toCharacterObject("A")  = 'A'
+     *   CharUtils.toCharacterObject("BA") = 'B'
+     * 
+ * + * @param str the character to convert + * @return the Character value of the first letter of the String + */ + public static Character toCharacterObject(final String str) { + if (StringUtils.isEmpty(str)) { + return null; + } + return Character.valueOf(str.charAt(0)); + } + + //----------------------------------------------------------------------- + /** + *

Converts the Character to a char throwing an exception for {@code null}.

+ * + *
+     *   CharUtils.toChar(' ')  = ' '
+     *   CharUtils.toChar('A')  = 'A'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the char value of the Character + * @throws IllegalArgumentException if the Character is null + */ + public static char toChar(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The Character must not be null"); + } + return ch.charValue(); + } + + /** + *

Converts the Character to a char handling {@code null}.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar(' ', 'X')  = ' '
+     *   CharUtils.toChar('A', 'X')  = 'A'
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the Character or the default if null + */ + public static char toChar(final Character ch, final char defaultValue) { + if (ch == null) { + return defaultValue; + } + return ch.charValue(); + } + + //----------------------------------------------------------------------- + /** + *

Converts the String to a char using the first character, throwing + * an exception on empty Strings.

+ * + *
+     *   CharUtils.toChar("A")  = 'A'
+     *   CharUtils.toChar("BA") = 'B'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     *   CharUtils.toChar("")   throws IllegalArgumentException
+     * 
+ * + * @param str the character to convert + * @return the char value of the first letter of the String + * @throws IllegalArgumentException if the String is empty + */ + public static char toChar(final String str) { + if (StringUtils.isEmpty(str)) { + throw new IllegalArgumentException("The String must not be empty"); + } + return str.charAt(0); + } + + /** + *

Converts the String to a char using the first character, defaulting + * the value on empty Strings.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar("", 'X')   = 'X'
+     *   CharUtils.toChar("A", 'X')  = 'A'
+     *   CharUtils.toChar("BA", 'X') = 'B'
+     * 
+ * + * @param str the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the first letter of the String or the default if null + */ + public static char toChar(final String str, final char defaultValue) { + if (StringUtils.isEmpty(str)) { + return defaultValue; + } + return str.charAt(0); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the int value of the character + * @throws IllegalArgumentException if the character is not ASCII numeric + */ + public static int toIntValue(final char ch) { + if (isAsciiNumeric(ch) == false) { + throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'"); + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final char ch, final int defaultValue) { + if (isAsciiNumeric(ch) == false) { + return defaultValue; + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue(null) throws IllegalArgumentException
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert, not null + * @return the int value of the character + * @throws IllegalArgumentException if the Character is not ASCII numeric or is null + */ + public static int toIntValue(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The character must not be null"); + } + return toIntValue(ch.charValue()); + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue(null, -1) = -1
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final Character ch, final int defaultValue) { + if (ch == null) { + return defaultValue; + } + return toIntValue(ch.charValue(), defaultValue); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final char ch) { + if (ch < 128) { + return CHAR_STRING_ARRAY[ch]; + } + return new String(new char[] {ch}); + } + + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.toString(null) = null
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ +/** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+ * CharUtils.toString(null) = null
+ * CharUtils.toString(' ')  = " "
+ * CharUtils.toString('A')  = "A"
+ * 
+ * + * @param ch + * the character to convert + * @return a String containing the one specified character + */ +public static java.lang.String toString(final java.lang.Character ch) { + { + return org.apache.commons.lang3.CharUtils.toString(/* NPEX_NULL_EXP */ + ch.charValue()); + } +} + + //-------------------------------------------------------------------------- + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *
+     *   CharUtils.unicodeEscaped(' ') = "\u0020"
+     *   CharUtils.unicodeEscaped('A') = "\u0041"
+     * 
+ * + * @param ch the character to convert + * @return the escaped Unicode string + */ + public static String unicodeEscaped(final char ch) { + StringBuilder sb = new StringBuilder(6); + sb.append("\\u"); + sb.append(HEX_DIGITS[(ch >> 12) & 15]); + sb.append(HEX_DIGITS[(ch >> 8) & 15]); + sb.append(HEX_DIGITS[(ch >> 4) & 15]); + sb.append(HEX_DIGITS[(ch) & 15]); + return sb.toString(); + } + + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.unicodeEscaped(null) = null
+     *   CharUtils.unicodeEscaped(' ')  = "\u0020"
+     *   CharUtils.unicodeEscaped('A')  = "\u0041"
+     * 
+ * + * @param ch the character to convert, may be null + * @return the escaped Unicode string, null if null input + */ + public static String unicodeEscaped(final Character ch) { + if (ch == null) { + return null; + } + return unicodeEscaped(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

Checks whether the character is ASCII 7 bit.

+ * + *
+     *   CharUtils.isAscii('a')  = true
+     *   CharUtils.isAscii('A')  = true
+     *   CharUtils.isAscii('3')  = true
+     *   CharUtils.isAscii('-')  = true
+     *   CharUtils.isAscii('\n') = true
+     *   CharUtils.isAscii('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 128 + */ + public static boolean isAscii(final char ch) { + return ch < 128; + } + + /** + *

Checks whether the character is ASCII 7 bit printable.

+ * + *
+     *   CharUtils.isAsciiPrintable('a')  = true
+     *   CharUtils.isAsciiPrintable('A')  = true
+     *   CharUtils.isAsciiPrintable('3')  = true
+     *   CharUtils.isAsciiPrintable('-')  = true
+     *   CharUtils.isAsciiPrintable('\n') = false
+     *   CharUtils.isAsciiPrintable('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 32 and 126 inclusive + */ + public static boolean isAsciiPrintable(final char ch) { + return ch >= 32 && ch < 127; + } + + /** + *

Checks whether the character is ASCII 7 bit control.

+ * + *
+     *   CharUtils.isAsciiControl('a')  = false
+     *   CharUtils.isAsciiControl('A')  = false
+     *   CharUtils.isAsciiControl('3')  = false
+     *   CharUtils.isAsciiControl('-')  = false
+     *   CharUtils.isAsciiControl('\n') = true
+     *   CharUtils.isAsciiControl('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 32 or equals 127 + */ + public static boolean isAsciiControl(final char ch) { + return ch < 32 || ch == 127; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic.

+ * + *
+     *   CharUtils.isAsciiAlpha('a')  = true
+     *   CharUtils.isAsciiAlpha('A')  = true
+     *   CharUtils.isAsciiAlpha('3')  = false
+     *   CharUtils.isAsciiAlpha('-')  = false
+     *   CharUtils.isAsciiAlpha('\n') = false
+     *   CharUtils.isAsciiAlpha('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlpha(final char ch) { + return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch); + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic upper case.

+ * + *
+     *   CharUtils.isAsciiAlphaUpper('a')  = false
+     *   CharUtils.isAsciiAlphaUpper('A')  = true
+     *   CharUtils.isAsciiAlphaUpper('3')  = false
+     *   CharUtils.isAsciiAlphaUpper('-')  = false
+     *   CharUtils.isAsciiAlphaUpper('\n') = false
+     *   CharUtils.isAsciiAlphaUpper('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 inclusive + */ + public static boolean isAsciiAlphaUpper(final char ch) { + return ch >= 'A' && ch <= 'Z'; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic lower case.

+ * + *
+     *   CharUtils.isAsciiAlphaLower('a')  = true
+     *   CharUtils.isAsciiAlphaLower('A')  = false
+     *   CharUtils.isAsciiAlphaLower('3')  = false
+     *   CharUtils.isAsciiAlphaLower('-')  = false
+     *   CharUtils.isAsciiAlphaLower('\n') = false
+     *   CharUtils.isAsciiAlphaLower('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 97 and 122 inclusive + */ + public static boolean isAsciiAlphaLower(final char ch) { + return ch >= 'a' && ch <= 'z'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiNumeric('a')  = false
+     *   CharUtils.isAsciiNumeric('A')  = false
+     *   CharUtils.isAsciiNumeric('3')  = true
+     *   CharUtils.isAsciiNumeric('-')  = false
+     *   CharUtils.isAsciiNumeric('\n') = false
+     *   CharUtils.isAsciiNumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 inclusive + */ + public static boolean isAsciiNumeric(final char ch) { + return ch >= '0' && ch <= '9'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiAlphanumeric('a')  = true
+     *   CharUtils.isAsciiAlphanumeric('A')  = true
+     *   CharUtils.isAsciiAlphanumeric('3')  = true
+     *   CharUtils.isAsciiAlphanumeric('-')  = false
+     *   CharUtils.isAsciiAlphanumeric('\n') = false
+     *   CharUtils.isAsciiAlphanumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlphanumeric(final char ch) { + return isAsciiAlpha(ch) || isAsciiNumeric(ch); + } + + /** + *

Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code char} to compare + * @param y the second {@code char} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(char x, char y) { + return x-y; + } +} diff --git a/Java/commons-lang-CharUtils_333/metadata.json b/Java/commons-lang-CharUtils_333/metadata.json new file mode 100644 index 000000000..35c06f2ee --- /dev/null +++ b/Java/commons-lang-CharUtils_333/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharUtils_333", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 353, + "npe_method": "toString", + "deref_field": "ch", + "npe_class": "CharUtils", + "repo": "commons-lang", + "bug_id": "CharUtils_333" + } +} diff --git a/Java/commons-lang-CharUtils_333/npe.json b/Java/commons-lang-CharUtils_333/npe.json new file mode 100644 index 000000000..fb92d4f1c --- /dev/null +++ b/Java/commons-lang-CharUtils_333/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 353, + "npe_method": "toString", + "deref_field": "ch", + "npe_class": "CharUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-CharUtils_380/Dockerfile b/Java/commons-lang-CharUtils_380/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CharUtils_380/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CharUtils_380/buggy.java b/Java/commons-lang-CharUtils_380/buggy.java new file mode 100644 index 000000000..bfb410543 --- /dev/null +++ b/Java/commons-lang-CharUtils_380/buggy.java @@ -0,0 +1,569 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3; + +/** + *

Operations on char primitives and Character objects.

+ * + *

This class tries to handle {@code null} input gracefully. + * An exception will not be thrown for a {@code null} input. + * Each method documents its behaviour in more detail.

+ * + *

#ThreadSafe#

+ * @since 2.1 + */ +public class CharUtils { + + private static final String[] CHAR_STRING_ARRAY = new String[128]; + + private static final char[] HEX_DIGITS = new char[] {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; + + /** + * {@code \u000a} linefeed LF ('\n'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char LF = '\n'; + + /** + * {@code \u000d} carriage return CR ('\r'). + * + * @see JLF: Escape Sequences + * for Character and String Literals + * @since 2.2 + */ + public static final char CR = '\r'; + + + static { + for (char c = 0; c < CHAR_STRING_ARRAY.length; c++) { + CHAR_STRING_ARRAY[c] = String.valueOf(c); + } + } + + /** + *

{@code CharUtils} instances should NOT be constructed in standard programming. + * Instead, the class should be used as {@code CharUtils.toString('c');}.

+ * + *

This constructor is public to permit tools that require a JavaBean instance + * to operate.

+ */ + public CharUtils() { + super(); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to a Character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(' ')  = ' '
+     *   CharUtils.toCharacterObject('A')  = 'A'
+     * 
+ * + * @deprecated Java 5 introduced {@link Character#valueOf(char)} which caches chars 0 through 127. + * @param ch the character to convert + * @return a Character of the specified character + */ + @Deprecated + public static Character toCharacterObject(final char ch) { + return Character.valueOf(ch); + } + + /** + *

Converts the String to a Character using the first character, returning + * null for empty Strings.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same Character object each time.

+ * + *
+     *   CharUtils.toCharacterObject(null) = null
+     *   CharUtils.toCharacterObject("")   = null
+     *   CharUtils.toCharacterObject("A")  = 'A'
+     *   CharUtils.toCharacterObject("BA") = 'B'
+     * 
+ * + * @param str the character to convert + * @return the Character value of the first letter of the String + */ + public static Character toCharacterObject(final String str) { + if (StringUtils.isEmpty(str)) { + return null; + } + return Character.valueOf(str.charAt(0)); + } + + //----------------------------------------------------------------------- + /** + *

Converts the Character to a char throwing an exception for {@code null}.

+ * + *
+     *   CharUtils.toChar(' ')  = ' '
+     *   CharUtils.toChar('A')  = 'A'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the char value of the Character + * @throws IllegalArgumentException if the Character is null + */ + public static char toChar(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The Character must not be null"); + } + return ch.charValue(); + } + + /** + *

Converts the Character to a char handling {@code null}.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar(' ', 'X')  = ' '
+     *   CharUtils.toChar('A', 'X')  = 'A'
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the Character or the default if null + */ + public static char toChar(final Character ch, final char defaultValue) { + if (ch == null) { + return defaultValue; + } + return ch.charValue(); + } + + //----------------------------------------------------------------------- + /** + *

Converts the String to a char using the first character, throwing + * an exception on empty Strings.

+ * + *
+     *   CharUtils.toChar("A")  = 'A'
+     *   CharUtils.toChar("BA") = 'B'
+     *   CharUtils.toChar(null) throws IllegalArgumentException
+     *   CharUtils.toChar("")   throws IllegalArgumentException
+     * 
+ * + * @param str the character to convert + * @return the char value of the first letter of the String + * @throws IllegalArgumentException if the String is empty + */ + public static char toChar(final String str) { + if (StringUtils.isEmpty(str)) { + throw new IllegalArgumentException("The String must not be empty"); + } + return str.charAt(0); + } + + /** + *

Converts the String to a char using the first character, defaulting + * the value on empty Strings.

+ * + *
+     *   CharUtils.toChar(null, 'X') = 'X'
+     *   CharUtils.toChar("", 'X')   = 'X'
+     *   CharUtils.toChar("A", 'X')  = 'A'
+     *   CharUtils.toChar("BA", 'X') = 'B'
+     * 
+ * + * @param str the character to convert + * @param defaultValue the value to use if the Character is null + * @return the char value of the first letter of the String or the default if null + */ + public static char toChar(final String str, final char defaultValue) { + if (StringUtils.isEmpty(str)) { + return defaultValue; + } + return str.charAt(0); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert + * @return the int value of the character + * @throws IllegalArgumentException if the character is not ASCII numeric + */ + public static int toIntValue(final char ch) { + if (isAsciiNumeric(ch) == false) { + throw new IllegalArgumentException("The character " + ch + " is not in the range '0' - '9'"); + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final char ch, final int defaultValue) { + if (isAsciiNumeric(ch) == false) { + return defaultValue; + } + return ch - 48; + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue('3')  = 3
+     *   CharUtils.toIntValue(null) throws IllegalArgumentException
+     *   CharUtils.toIntValue('A')  throws IllegalArgumentException
+     * 
+ * + * @param ch the character to convert, not null + * @return the int value of the character + * @throws IllegalArgumentException if the Character is not ASCII numeric or is null + */ + public static int toIntValue(final Character ch) { + if (ch == null) { + throw new IllegalArgumentException("The character must not be null"); + } + return toIntValue(ch.charValue()); + } + + /** + *

Converts the character to the Integer it represents, throwing an + * exception if the character is not numeric.

+ * + *

This method coverts the char '1' to the int 1 and so on.

+ * + *
+     *   CharUtils.toIntValue(null, -1) = -1
+     *   CharUtils.toIntValue('3', -1)  = 3
+     *   CharUtils.toIntValue('A', -1)  = -1
+     * 
+ * + * @param ch the character to convert + * @param defaultValue the default value to use if the character is not numeric + * @return the int value of the character + */ + public static int toIntValue(final Character ch, final int defaultValue) { + if (ch == null) { + return defaultValue; + } + return toIntValue(ch.charValue(), defaultValue); + } + + //----------------------------------------------------------------------- + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final char ch) { + if (ch < 128) { + return CHAR_STRING_ARRAY[ch]; + } + return new String(new char[] {ch}); + } + + /** + *

Converts the character to a String that contains the one character.

+ * + *

For ASCII 7 bit characters, this uses a cache that will return the + * same String object each time.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.toString(null) = null
+     *   CharUtils.toString(' ')  = " "
+     *   CharUtils.toString('A')  = "A"
+     * 
+ * + * @param ch the character to convert + * @return a String containing the one specified character + */ + public static String toString(final Character ch) { + if (ch == null) { + return null; + } + return toString(ch.charValue()); + } + + //-------------------------------------------------------------------------- + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *
+     *   CharUtils.unicodeEscaped(' ') = "\u0020"
+     *   CharUtils.unicodeEscaped('A') = "\u0041"
+     * 
+ * + * @param ch the character to convert + * @return the escaped Unicode string + */ + public static String unicodeEscaped(final char ch) { + StringBuilder sb = new StringBuilder(6); + sb.append("\\u"); + sb.append(HEX_DIGITS[(ch >> 12) & 15]); + sb.append(HEX_DIGITS[(ch >> 8) & 15]); + sb.append(HEX_DIGITS[(ch >> 4) & 15]); + sb.append(HEX_DIGITS[(ch) & 15]); + return sb.toString(); + } + + /** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+     *   CharUtils.unicodeEscaped(null) = null
+     *   CharUtils.unicodeEscaped(' ')  = "\u0020"
+     *   CharUtils.unicodeEscaped('A')  = "\u0041"
+     * 
+ * + * @param ch the character to convert, may be null + * @return the escaped Unicode string, null if null input + */ +/** + *

Converts the string to the Unicode format '\u0020'.

+ * + *

This format is the Java source code format.

+ * + *

If {@code null} is passed in, {@code null} will be returned.

+ * + *
+ * CharUtils.unicodeEscaped(null) = null
+ * CharUtils.unicodeEscaped(' ')  = "\u0020"
+ * CharUtils.unicodeEscaped('A')  = "\u0041"
+ * 
+ * + * @param ch + * the character to convert, may be null + * @return the escaped Unicode string, null if null input + */ +public static java.lang.String unicodeEscaped(final java.lang.Character ch) { + { + return org.apache.commons.lang3.CharUtils.unicodeEscaped(/* NPEX_NULL_EXP */ + ch.charValue()); + } +} + + //-------------------------------------------------------------------------- + /** + *

Checks whether the character is ASCII 7 bit.

+ * + *
+     *   CharUtils.isAscii('a')  = true
+     *   CharUtils.isAscii('A')  = true
+     *   CharUtils.isAscii('3')  = true
+     *   CharUtils.isAscii('-')  = true
+     *   CharUtils.isAscii('\n') = true
+     *   CharUtils.isAscii('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 128 + */ + public static boolean isAscii(final char ch) { + return ch < 128; + } + + /** + *

Checks whether the character is ASCII 7 bit printable.

+ * + *
+     *   CharUtils.isAsciiPrintable('a')  = true
+     *   CharUtils.isAsciiPrintable('A')  = true
+     *   CharUtils.isAsciiPrintable('3')  = true
+     *   CharUtils.isAsciiPrintable('-')  = true
+     *   CharUtils.isAsciiPrintable('\n') = false
+     *   CharUtils.isAsciiPrintable('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 32 and 126 inclusive + */ + public static boolean isAsciiPrintable(final char ch) { + return ch >= 32 && ch < 127; + } + + /** + *

Checks whether the character is ASCII 7 bit control.

+ * + *
+     *   CharUtils.isAsciiControl('a')  = false
+     *   CharUtils.isAsciiControl('A')  = false
+     *   CharUtils.isAsciiControl('3')  = false
+     *   CharUtils.isAsciiControl('-')  = false
+     *   CharUtils.isAsciiControl('\n') = true
+     *   CharUtils.isAsciiControl('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if less than 32 or equals 127 + */ + public static boolean isAsciiControl(final char ch) { + return ch < 32 || ch == 127; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic.

+ * + *
+     *   CharUtils.isAsciiAlpha('a')  = true
+     *   CharUtils.isAsciiAlpha('A')  = true
+     *   CharUtils.isAsciiAlpha('3')  = false
+     *   CharUtils.isAsciiAlpha('-')  = false
+     *   CharUtils.isAsciiAlpha('\n') = false
+     *   CharUtils.isAsciiAlpha('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlpha(final char ch) { + return isAsciiAlphaUpper(ch) || isAsciiAlphaLower(ch); + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic upper case.

+ * + *
+     *   CharUtils.isAsciiAlphaUpper('a')  = false
+     *   CharUtils.isAsciiAlphaUpper('A')  = true
+     *   CharUtils.isAsciiAlphaUpper('3')  = false
+     *   CharUtils.isAsciiAlphaUpper('-')  = false
+     *   CharUtils.isAsciiAlphaUpper('\n') = false
+     *   CharUtils.isAsciiAlphaUpper('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 65 and 90 inclusive + */ + public static boolean isAsciiAlphaUpper(final char ch) { + return ch >= 'A' && ch <= 'Z'; + } + + /** + *

Checks whether the character is ASCII 7 bit alphabetic lower case.

+ * + *
+     *   CharUtils.isAsciiAlphaLower('a')  = true
+     *   CharUtils.isAsciiAlphaLower('A')  = false
+     *   CharUtils.isAsciiAlphaLower('3')  = false
+     *   CharUtils.isAsciiAlphaLower('-')  = false
+     *   CharUtils.isAsciiAlphaLower('\n') = false
+     *   CharUtils.isAsciiAlphaLower('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 97 and 122 inclusive + */ + public static boolean isAsciiAlphaLower(final char ch) { + return ch >= 'a' && ch <= 'z'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiNumeric('a')  = false
+     *   CharUtils.isAsciiNumeric('A')  = false
+     *   CharUtils.isAsciiNumeric('3')  = true
+     *   CharUtils.isAsciiNumeric('-')  = false
+     *   CharUtils.isAsciiNumeric('\n') = false
+     *   CharUtils.isAsciiNumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 inclusive + */ + public static boolean isAsciiNumeric(final char ch) { + return ch >= '0' && ch <= '9'; + } + + /** + *

Checks whether the character is ASCII 7 bit numeric.

+ * + *
+     *   CharUtils.isAsciiAlphanumeric('a')  = true
+     *   CharUtils.isAsciiAlphanumeric('A')  = true
+     *   CharUtils.isAsciiAlphanumeric('3')  = true
+     *   CharUtils.isAsciiAlphanumeric('-')  = false
+     *   CharUtils.isAsciiAlphanumeric('\n') = false
+     *   CharUtils.isAsciiAlphanumeric('©') = false
+     * 
+ * + * @param ch the character to check + * @return true if between 48 and 57 or 65 and 90 or 97 and 122 inclusive + */ + public static boolean isAsciiAlphanumeric(final char ch) { + return isAsciiAlpha(ch) || isAsciiNumeric(ch); + } + + /** + *

Compares two {@code char} values numerically. This is the same functionality as provided in Java 7.

+ * + * @param x the first {@code char} to compare + * @param y the second {@code char} to compare + * @return the value {@code 0} if {@code x == y}; + * a value less than {@code 0} if {@code x < y}; and + * a value greater than {@code 0} if {@code x > y} + * @since 3.4 + */ + public static int compare(char x, char y) { + return x-y; + } +} diff --git a/Java/commons-lang-CharUtils_380/metadata.json b/Java/commons-lang-CharUtils_380/metadata.json new file mode 100644 index 000000000..3bdcd6e4e --- /dev/null +++ b/Java/commons-lang-CharUtils_380/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CharUtils_380", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 399, + "npe_method": "unicodeEscaped", + "deref_field": "ch", + "npe_class": "CharUtils", + "repo": "commons-lang", + "bug_id": "CharUtils_380" + } +} diff --git a/Java/commons-lang-CharUtils_380/npe.json b/Java/commons-lang-CharUtils_380/npe.json new file mode 100644 index 000000000..dd2ad1bce --- /dev/null +++ b/Java/commons-lang-CharUtils_380/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/CharUtils.java", + "line": 399, + "npe_method": "unicodeEscaped", + "deref_field": "ch", + "npe_class": "CharUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_412/Dockerfile b/Java/commons-lang-CompareToBuilder_412/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_412/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_412/buggy.java b/Java/commons-lang-CompareToBuilder_412/buggy.java new file mode 100644 index 000000000..ea4c7fd01 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_412/buggy.java @@ -0,0 +1,1061 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ +/** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs + * left-hand object + * @param rhs + * right-hand object + * @param comparator + * Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException + * if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final java.lang.Object lhs, final java.lang.Object rhs, final java.util.Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + { + if (rhs == null) { + comparison = +1; + return this; + } + if (/* NPEX_NULL_EXP */ + lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else // the simple case, not an array, just test the element + if (comparator == null) { + // assume this can be done; if not throw CCE as per Javadoc + @java.lang.SuppressWarnings("unchecked") + final java.lang.Comparable comparable = ((java.lang.Comparable) (lhs)); + comparison = comparable.compareTo(rhs); + } else { + // assume this can be done; if not throw CCE as per Javadoc + @java.lang.SuppressWarnings("unchecked") + final java.util.Comparator comparator2 = ((java.util.Comparator) (comparator)); + comparison = comparator2.compare(lhs, rhs); + } + return this; + } +} + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_412/metadata.json b/Java/commons-lang-CompareToBuilder_412/metadata.json new file mode 100644 index 000000000..764df5654 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_412/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_412", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 447, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_412" + } +} diff --git a/Java/commons-lang-CompareToBuilder_412/npe.json b/Java/commons-lang-CompareToBuilder_412/npe.json new file mode 100644 index 000000000..2c88cf8f3 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_412/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 447, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_416/Dockerfile b/Java/commons-lang-CompareToBuilder_416/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_416/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_416/buggy.java b/Java/commons-lang-CompareToBuilder_416/buggy.java new file mode 100644 index 000000000..d6e8fb803 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_416/buggy.java @@ -0,0 +1,1061 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ +/** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs + * left-hand object + * @param rhs + * right-hand object + * @param comparator + * Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException + * if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final java.lang.Object lhs, final java.lang.Object rhs, final java.util.Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + { + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, /* NPEX_NULL_EXP */ + rhs, comparator); + } else // the simple case, not an array, just test the element + if (comparator == null) { + // assume this can be done; if not throw CCE as per Javadoc + @java.lang.SuppressWarnings("unchecked") + final java.lang.Comparable comparable = ((java.lang.Comparable) (lhs)); + comparison = comparable.compareTo(rhs); + } else { + // assume this can be done; if not throw CCE as per Javadoc + @java.lang.SuppressWarnings("unchecked") + final java.util.Comparator comparator2 = ((java.util.Comparator) (comparator)); + comparison = comparator2.compare(lhs, rhs); + } + return this; + } +} + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_416/metadata.json b/Java/commons-lang-CompareToBuilder_416/metadata.json new file mode 100644 index 000000000..1795de28e --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_416/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_416", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 449, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_416" + } +} diff --git a/Java/commons-lang-CompareToBuilder_416/npe.json b/Java/commons-lang-CompareToBuilder_416/npe.json new file mode 100644 index 000000000..036ea142f --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_416/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 449, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_666/Dockerfile b/Java/commons-lang-CompareToBuilder_666/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_666/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_666/buggy.java b/Java/commons-lang-CompareToBuilder_666/buggy.java new file mode 100644 index 000000000..8a5b77c92 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_666/buggy.java @@ -0,0 +1,1059 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ +/** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @param comparator + * Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException + * if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final java.lang.Object[] lhs, final java.lang.Object[] rhs, final java.util.Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + { + if (rhs == null) { + comparison = +1; + return this; + } + if (/* NPEX_NULL_EXP */ + lhs.length != rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_666/metadata.json b/Java/commons-lang-CompareToBuilder_666/metadata.json new file mode 100644 index 000000000..f78a3d2c1 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_666/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_666", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 699, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_666" + } +} diff --git a/Java/commons-lang-CompareToBuilder_666/npe.json b/Java/commons-lang-CompareToBuilder_666/npe.json new file mode 100644 index 000000000..7ec6222bf --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_666/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 699, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_670/Dockerfile b/Java/commons-lang-CompareToBuilder_670/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_670/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_670/buggy.java b/Java/commons-lang-CompareToBuilder_670/buggy.java new file mode 100644 index 000000000..760c340bc --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_670/buggy.java @@ -0,0 +1,1059 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ +/** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @param comparator + * Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException + * if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final java.lang.Object[] lhs, final java.lang.Object[] rhs, final java.util.Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + { + if (lhs.length != /* NPEX_NULL_EXP */ + rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_670/metadata.json b/Java/commons-lang-CompareToBuilder_670/metadata.json new file mode 100644 index 000000000..fc70b892c --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_670/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_670", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 699, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_670" + } +} diff --git a/Java/commons-lang-CompareToBuilder_670/npe.json b/Java/commons-lang-CompareToBuilder_670/npe.json new file mode 100644 index 000000000..68fadaf00 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_670/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 699, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_706/Dockerfile b/Java/commons-lang-CompareToBuilder_706/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_706/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_706/buggy.java b/Java/commons-lang-CompareToBuilder_706/buggy.java new file mode 100644 index 000000000..1b9df6406 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_706/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + { + if (rhs == null) { + comparison = +1; + return this; + } + if (/* NPEX_NULL_EXP */ + lhs.length != rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_706/metadata.json b/Java/commons-lang-CompareToBuilder_706/metadata.json new file mode 100644 index 000000000..02e2bf2c4 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_706/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_706", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 729, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_706" + } +} diff --git a/Java/commons-lang-CompareToBuilder_706/npe.json b/Java/commons-lang-CompareToBuilder_706/npe.json new file mode 100644 index 000000000..e24e2c754 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_706/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 729, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_710/Dockerfile b/Java/commons-lang-CompareToBuilder_710/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_710/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_710/buggy.java b/Java/commons-lang-CompareToBuilder_710/buggy.java new file mode 100644 index 000000000..e62f15745 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_710/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + { + if (lhs.length != /* NPEX_NULL_EXP */ + rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_710/metadata.json b/Java/commons-lang-CompareToBuilder_710/metadata.json new file mode 100644 index 000000000..389209f6c --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_710/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_710", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 729, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_710" + } +} diff --git a/Java/commons-lang-CompareToBuilder_710/npe.json b/Java/commons-lang-CompareToBuilder_710/npe.json new file mode 100644 index 000000000..7abcd6c97 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_710/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 729, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_746/Dockerfile b/Java/commons-lang-CompareToBuilder_746/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_746/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_746/buggy.java b/Java/commons-lang-CompareToBuilder_746/buggy.java new file mode 100644 index 000000000..b256f2235 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_746/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + { + if (rhs == null) { + comparison = +1; + return this; + } + if (/* NPEX_NULL_EXP */ + lhs.length != rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_746/metadata.json b/Java/commons-lang-CompareToBuilder_746/metadata.json new file mode 100644 index 000000000..d8770ac76 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_746/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_746", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 769, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_746" + } +} diff --git a/Java/commons-lang-CompareToBuilder_746/npe.json b/Java/commons-lang-CompareToBuilder_746/npe.json new file mode 100644 index 000000000..15bbce145 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_746/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 769, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_750/Dockerfile b/Java/commons-lang-CompareToBuilder_750/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_750/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_750/buggy.java b/Java/commons-lang-CompareToBuilder_750/buggy.java new file mode 100644 index 000000000..2febe5341 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_750/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + { + if (lhs.length != /* NPEX_NULL_EXP */ + rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_750/metadata.json b/Java/commons-lang-CompareToBuilder_750/metadata.json new file mode 100644 index 000000000..3b3d5df40 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_750/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_750", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 769, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_750" + } +} diff --git a/Java/commons-lang-CompareToBuilder_750/npe.json b/Java/commons-lang-CompareToBuilder_750/npe.json new file mode 100644 index 000000000..d93e1e883 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_750/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 769, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_786/Dockerfile b/Java/commons-lang-CompareToBuilder_786/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_786/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_786/buggy.java b/Java/commons-lang-CompareToBuilder_786/buggy.java new file mode 100644 index 000000000..af66ac008 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_786/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + { + if (rhs == null) { + comparison = +1; + return this; + } + if (/* NPEX_NULL_EXP */ + lhs.length != rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_786/metadata.json b/Java/commons-lang-CompareToBuilder_786/metadata.json new file mode 100644 index 000000000..09945f4b1 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_786/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_786", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 809, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_786" + } +} diff --git a/Java/commons-lang-CompareToBuilder_786/npe.json b/Java/commons-lang-CompareToBuilder_786/npe.json new file mode 100644 index 000000000..18e46a272 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_786/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 809, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_790/Dockerfile b/Java/commons-lang-CompareToBuilder_790/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_790/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_790/buggy.java b/Java/commons-lang-CompareToBuilder_790/buggy.java new file mode 100644 index 000000000..161a3b566 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_790/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + { + if (lhs.length != /* NPEX_NULL_EXP */ + rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_790/metadata.json b/Java/commons-lang-CompareToBuilder_790/metadata.json new file mode 100644 index 000000000..1afe6c1f6 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_790/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_790", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 809, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_790" + } +} diff --git a/Java/commons-lang-CompareToBuilder_790/npe.json b/Java/commons-lang-CompareToBuilder_790/npe.json new file mode 100644 index 000000000..6e26e813f --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_790/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 809, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_826/Dockerfile b/Java/commons-lang-CompareToBuilder_826/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_826/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_826/buggy.java b/Java/commons-lang-CompareToBuilder_826/buggy.java new file mode 100644 index 000000000..3e9c4ec0f --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_826/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + { + if (rhs == null) { + comparison = +1; + return this; + } + if (/* NPEX_NULL_EXP */ + lhs.length != rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_826/metadata.json b/Java/commons-lang-CompareToBuilder_826/metadata.json new file mode 100644 index 000000000..a610fc6f3 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_826/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_826", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 849, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_826" + } +} diff --git a/Java/commons-lang-CompareToBuilder_826/npe.json b/Java/commons-lang-CompareToBuilder_826/npe.json new file mode 100644 index 000000000..90976c335 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_826/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 849, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_830/Dockerfile b/Java/commons-lang-CompareToBuilder_830/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_830/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_830/buggy.java b/Java/commons-lang-CompareToBuilder_830/buggy.java new file mode 100644 index 000000000..77d88d125 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_830/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + { + if (lhs.length != /* NPEX_NULL_EXP */ + rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_830/metadata.json b/Java/commons-lang-CompareToBuilder_830/metadata.json new file mode 100644 index 000000000..f1600ee50 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_830/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_830", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 849, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_830" + } +} diff --git a/Java/commons-lang-CompareToBuilder_830/npe.json b/Java/commons-lang-CompareToBuilder_830/npe.json new file mode 100644 index 000000000..f4369e8ea --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_830/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 849, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_866/Dockerfile b/Java/commons-lang-CompareToBuilder_866/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_866/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_866/buggy.java b/Java/commons-lang-CompareToBuilder_866/buggy.java new file mode 100644 index 000000000..896470c29 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_866/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + { + if (rhs == null) { + comparison = +1; + return this; + } + if (/* NPEX_NULL_EXP */ + lhs.length != rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_866/metadata.json b/Java/commons-lang-CompareToBuilder_866/metadata.json new file mode 100644 index 000000000..7afec5782 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_866/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_866", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 889, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_866" + } +} diff --git a/Java/commons-lang-CompareToBuilder_866/npe.json b/Java/commons-lang-CompareToBuilder_866/npe.json new file mode 100644 index 000000000..b2275c6bf --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_866/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 889, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_870/Dockerfile b/Java/commons-lang-CompareToBuilder_870/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_870/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_870/buggy.java b/Java/commons-lang-CompareToBuilder_870/buggy.java new file mode 100644 index 000000000..ef809a64e --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_870/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + { + if (lhs.length != /* NPEX_NULL_EXP */ + rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_870/metadata.json b/Java/commons-lang-CompareToBuilder_870/metadata.json new file mode 100644 index 000000000..f86fc652b --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_870/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_870", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 889, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_870" + } +} diff --git a/Java/commons-lang-CompareToBuilder_870/npe.json b/Java/commons-lang-CompareToBuilder_870/npe.json new file mode 100644 index 000000000..b6aa0bf92 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_870/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 889, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_906/Dockerfile b/Java/commons-lang-CompareToBuilder_906/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_906/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_906/buggy.java b/Java/commons-lang-CompareToBuilder_906/buggy.java new file mode 100644 index 000000000..f961129fd --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_906/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + { + if (rhs == null) { + comparison = +1; + return this; + } + if (/* NPEX_NULL_EXP */ + lhs.length != rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_906/metadata.json b/Java/commons-lang-CompareToBuilder_906/metadata.json new file mode 100644 index 000000000..04fddeff5 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_906/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_906", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 929, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_906" + } +} diff --git a/Java/commons-lang-CompareToBuilder_906/npe.json b/Java/commons-lang-CompareToBuilder_906/npe.json new file mode 100644 index 000000000..cf3dcaf84 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_906/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 929, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_910/Dockerfile b/Java/commons-lang-CompareToBuilder_910/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_910/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_910/buggy.java b/Java/commons-lang-CompareToBuilder_910/buggy.java new file mode 100644 index 000000000..e2be7c63e --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_910/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + { + if (lhs.length != /* NPEX_NULL_EXP */ + rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_910/metadata.json b/Java/commons-lang-CompareToBuilder_910/metadata.json new file mode 100644 index 000000000..0aa3c491a --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_910/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_910", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 929, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_910" + } +} diff --git a/Java/commons-lang-CompareToBuilder_910/npe.json b/Java/commons-lang-CompareToBuilder_910/npe.json new file mode 100644 index 000000000..34b5b2d7b --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_910/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 929, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_946/Dockerfile b/Java/commons-lang-CompareToBuilder_946/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_946/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_946/buggy.java b/Java/commons-lang-CompareToBuilder_946/buggy.java new file mode 100644 index 000000000..4475d57d1 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_946/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + { + if (rhs == null) { + comparison = +1; + return this; + } + if (/* NPEX_NULL_EXP */ + lhs.length != rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_946/metadata.json b/Java/commons-lang-CompareToBuilder_946/metadata.json new file mode 100644 index 000000000..bedaf43b9 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_946/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_946", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 969, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_946" + } +} diff --git a/Java/commons-lang-CompareToBuilder_946/npe.json b/Java/commons-lang-CompareToBuilder_946/npe.json new file mode 100644 index 000000000..d028c93d3 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_946/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 969, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_950/Dockerfile b/Java/commons-lang-CompareToBuilder_950/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_950/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_950/buggy.java b/Java/commons-lang-CompareToBuilder_950/buggy.java new file mode 100644 index 000000000..a1393f337 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_950/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + { + if (lhs.length != /* NPEX_NULL_EXP */ + rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_950/metadata.json b/Java/commons-lang-CompareToBuilder_950/metadata.json new file mode 100644 index 000000000..3996a4a91 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_950/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_950", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 969, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_950" + } +} diff --git a/Java/commons-lang-CompareToBuilder_950/npe.json b/Java/commons-lang-CompareToBuilder_950/npe.json new file mode 100644 index 000000000..25792e372 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_950/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 969, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_986/Dockerfile b/Java/commons-lang-CompareToBuilder_986/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_986/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_986/buggy.java b/Java/commons-lang-CompareToBuilder_986/buggy.java new file mode 100644 index 000000000..2dfcd1d6c --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_986/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + { + if (rhs == null) { + comparison = +1; + return this; + } + if (/* NPEX_NULL_EXP */ + lhs.length != rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_986/metadata.json b/Java/commons-lang-CompareToBuilder_986/metadata.json new file mode 100644 index 000000000..80dba154a --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_986/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_986", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 1009, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_986" + } +} diff --git a/Java/commons-lang-CompareToBuilder_986/npe.json b/Java/commons-lang-CompareToBuilder_986/npe.json new file mode 100644 index 000000000..625351174 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_986/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 1009, + "npe_method": "append", + "deref_field": "lhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-CompareToBuilder_990/Dockerfile b/Java/commons-lang-CompareToBuilder_990/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_990/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-CompareToBuilder_990/buggy.java b/Java/commons-lang-CompareToBuilder_990/buggy.java new file mode 100644 index 000000000..209757822 --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_990/buggy.java @@ -0,0 +1,1049 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.builder; + +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.util.Collection; +import java.util.Comparator; + +import org.apache.commons.lang3.ArrayUtils; + +/** + * Assists in implementing {@link java.lang.Comparable#compareTo(Object)} methods. + * + *

It is consistent with equals(Object) and + * hashcode() built with {@link EqualsBuilder} and + * {@link HashCodeBuilder}.

+ * + *

Two Objects that compare equal using equals(Object) should normally + * also compare equal using compareTo(Object).

+ * + *

All relevant fields should be included in the calculation of the + * comparison. Derived fields may be ignored. The same fields, in the same + * order, should be used in both compareTo(Object) and + * equals(Object).

+ * + *

To use this class write code as follows:

+ * + *
+ * public class MyClass {
+ *   String field1;
+ *   int field2;
+ *   boolean field3;
+ *
+ *   ...
+ *
+ *   public int compareTo(Object o) {
+ *     MyClass myClass = (MyClass) o;
+ *     return new CompareToBuilder()
+ *       .appendSuper(super.compareTo(o)
+ *       .append(this.field1, myClass.field1)
+ *       .append(this.field2, myClass.field2)
+ *       .append(this.field3, myClass.field3)
+ *       .toComparison();
+ *   }
+ * }
+ * 
+ * + *

Values are compared in the order they are appended to the builder. If any comparison returns + * a non-zero result, then that value will be the result returned by {@code toComparison()} and all + * subsequent comparisons are skipped.

+ * + *

Alternatively, there are {@link #reflectionCompare(Object, Object) reflectionCompare} methods that use + * reflection to determine the fields to append. Because fields can be private, + * reflectionCompare uses {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} to + * bypass normal access control checks. This will fail under a security manager, + * unless the appropriate permissions are set up correctly. It is also + * slower than appending explicitly.

+ * + *

A typical implementation of compareTo(Object) using + * reflectionCompare looks like:

+ + *
+ * public int compareTo(Object o) {
+ *   return CompareToBuilder.reflectionCompare(this, o);
+ * }
+ * 
+ * + *

The reflective methods compare object fields in the order returned by + * {@link Class#getDeclaredFields()}. The fields of the class are compared first, followed by those + * of its parent classes (in order from the bottom to the top of the class hierarchy).

+ * + * @see java.lang.Comparable + * @see java.lang.Object#equals(Object) + * @see java.lang.Object#hashCode() + * @see EqualsBuilder + * @see HashCodeBuilder + * @since 1.0 + */ +public class CompareToBuilder implements Builder { + + /** + * Current state of the comparison as appended fields are checked. + */ + private int comparison; + + /** + *

Constructor for CompareToBuilder.

+ * + *

Starts off assuming that the objects are equal. Multiple calls are + * then made to the various append methods, followed by a call to + * {@link #toComparison} to get the result.

+ */ + public CompareToBuilder() { + super(); + comparison = 0; + } + + //----------------------------------------------------------------------- + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • Transient members will be not be compared, as they are likely derived + * fields
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either (but not both) parameters are + * null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs) { + return reflectionCompare(lhs, rhs, false, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final boolean compareTransients) { + return reflectionCompare(lhs, rhs, compareTransients, null); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields Collection of String fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final Collection excludeFields) { + return reflectionCompare(lhs, rhs, ReflectionToStringBuilder.toNoNullStringArray(excludeFields)); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Superclass fields will be compared
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param excludeFields array of fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 + */ + public static int reflectionCompare(final Object lhs, final Object rhs, final String... excludeFields) { + return reflectionCompare(lhs, rhs, false, null, excludeFields); + } + + /** + *

Compares two Objects via reflection.

+ * + *

Fields can be private, thus AccessibleObject.setAccessible + * is used to bypass normal access control checks. This will fail under a + * security manager unless the appropriate permissions are set.

+ * + *
    + *
  • Static fields will not be compared
  • + *
  • If the compareTransients is true, + * compares transient members. Otherwise ignores them, as they + * are likely derived fields.
  • + *
  • Compares superclass fields up to and including reflectUpToClass. + * If reflectUpToClass is null, compares all superclass fields.
  • + *
+ * + *

If both lhs and rhs are null, + * they are considered equal.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param compareTransients whether to compare transient fields + * @param reflectUpToClass last superclass for which fields are compared + * @param excludeFields fields to exclude + * @return a negative integer, zero, or a positive integer as lhs + * is less than, equal to, or greater than rhs + * @throws NullPointerException if either lhs or rhs + * (but not both) is null + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.2 (2.0 as reflectionCompare(Object, Object, boolean, Class)) + */ + public static int reflectionCompare( + final Object lhs, + final Object rhs, + final boolean compareTransients, + final Class reflectUpToClass, + final String... excludeFields) { + + if (lhs == rhs) { + return 0; + } + if (lhs == null || rhs == null) { + throw new NullPointerException(); + } + Class lhsClazz = lhs.getClass(); + if (!lhsClazz.isInstance(rhs)) { + throw new ClassCastException(); + } + final CompareToBuilder compareToBuilder = new CompareToBuilder(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + while (lhsClazz.getSuperclass() != null && lhsClazz != reflectUpToClass) { + lhsClazz = lhsClazz.getSuperclass(); + reflectionAppend(lhs, rhs, lhsClazz, compareToBuilder, compareTransients, excludeFields); + } + return compareToBuilder.toComparison(); + } + + /** + *

Appends to builder the comparison of lhs + * to rhs using the fields defined in clazz.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param clazz Class that defines fields to be compared + * @param builder CompareToBuilder to append to + * @param useTransients whether to compare transient fields + * @param excludeFields fields to exclude + */ + private static void reflectionAppend( + final Object lhs, + final Object rhs, + final Class clazz, + final CompareToBuilder builder, + final boolean useTransients, + final String[] excludeFields) { + + final Field[] fields = clazz.getDeclaredFields(); + AccessibleObject.setAccessible(fields, true); + for (int i = 0; i < fields.length && builder.comparison == 0; i++) { + final Field f = fields[i]; + if (!ArrayUtils.contains(excludeFields, f.getName()) + && !f.getName().contains("$") + && (useTransients || !Modifier.isTransient(f.getModifiers())) + && !Modifier.isStatic(f.getModifiers())) { + try { + builder.append(f.get(lhs), f.get(rhs)); + } catch (final IllegalAccessException e) { + // This can't happen. Would get a Security exception instead. + // Throw a runtime exception in case the impossible happens. + throw new InternalError("Unexpected IllegalAccessException"); + } + } + } + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the compareTo(Object) + * result of the superclass.

+ * + * @param superCompareTo result of calling super.compareTo(Object) + * @return this - used to chain append calls + * @since 2.0 + */ + public CompareToBuilder appendSuper(final int superCompareTo) { + if (comparison != 0) { + return this; + } + comparison = superCompareTo; + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

lhs must either be an array or implement {@link Comparable}.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object lhs, final Object rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the comparison of + * two Objects.

+ * + *
    + *
  1. Check if lhs == rhs
  2. + *
  3. Check if either lhs or rhs is null, + * a null object is less than a non-null object
  4. + *
  5. Check the object contents
  6. + *
+ * + *

If lhs is an array, array comparison methods will be used. + * Otherwise comparator will be used to compare the objects. + * If comparator is null, lhs must + * implement {@link Comparable} instead.

+ * + * @param lhs left-hand object + * @param rhs right-hand object + * @param comparator Comparator used to compare the objects, + * null means treat lhs as Comparable + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object lhs, final Object rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.getClass().isArray()) { + // factor out array case in order to keep method small enough to be inlined + appendArray(lhs, rhs, comparator); + } else { + // the simple case, not an array, just test the element + if (comparator == null) { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparable comparable = (Comparable) lhs; + comparison = comparable.compareTo(rhs); + } else { + @SuppressWarnings("unchecked") // assume this can be done; if not throw CCE as per Javadoc + final Comparator comparator2 = (Comparator) comparator; + comparison = comparator2.compare(lhs, rhs); + } + } + return this; + } + + private void appendArray(final Object lhs, final Object rhs, final Comparator comparator) { + // switch on type of array, to dispatch to the correct handler + // handles multi dimensional arrays + // throws a ClassCastException if rhs is not the correct array type + if (lhs instanceof long[]) { + append((long[]) lhs, (long[]) rhs); + } else if (lhs instanceof int[]) { + append((int[]) lhs, (int[]) rhs); + } else if (lhs instanceof short[]) { + append((short[]) lhs, (short[]) rhs); + } else if (lhs instanceof char[]) { + append((char[]) lhs, (char[]) rhs); + } else if (lhs instanceof byte[]) { + append((byte[]) lhs, (byte[]) rhs); + } else if (lhs instanceof double[]) { + append((double[]) lhs, (double[]) rhs); + } else if (lhs instanceof float[]) { + append((float[]) lhs, (float[]) rhs); + } else if (lhs instanceof boolean[]) { + append((boolean[]) lhs, (boolean[]) rhs); + } else { + // not an array of primitives + // throws a ClassCastException if rhs is not an array + append((Object[]) lhs, (Object[]) rhs, comparator); + } + } + + //------------------------------------------------------------------------- + /** + * Appends to the builder the comparison of + * two longs. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long lhs, final long rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two ints. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int lhs, final int rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two shorts. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short lhs, final short rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two chars. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char lhs, final char rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + * Appends to the builder the comparison of + * two bytes. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte lhs, final byte rhs) { + if (comparison != 0) { + return this; + } + comparison = lhs < rhs ? -1 : lhs > rhs ? 1 : 0; + return this; + } + + /** + *

Appends to the builder the comparison of + * two doubles.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double lhs, final double rhs) { + if (comparison != 0) { + return this; + } + comparison = Double.compare(lhs, rhs); + return this; + } + + /** + *

Appends to the builder the comparison of + * two floats.

+ * + *

This handles NaNs, Infinities, and -0.0.

+ * + *

It is compatible with the hash code generated by + * HashCodeBuilder.

+ * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float lhs, final float rhs) { + if (comparison != 0) { + return this; + } + comparison = Float.compare(lhs, rhs); + return this; + } + + /** + * Appends to the builder the comparison of + * two booleanss. + * + * @param lhs left-hand value + * @param rhs right-hand value + * @return this - used to chain append calls + */ + public CompareToBuilder append(final boolean lhs, final boolean rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == false) { + comparison = -1; + } else { + comparison = +1; + } + return this; + } + + //----------------------------------------------------------------------- + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs) { + return append(lhs, rhs, null); + } + + /** + *

Appends to the builder the deep comparison of + * two Object arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a short length array is less than a long length array
  6. + *
  7. Check array contents element by element using {@link #append(Object, Object, Comparator)}
  8. + *
+ * + *

This method will also will be called for the top level of multi-dimensional, + * ragged, and multi-typed arrays.

+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @param comparator Comparator to use to compare the array elements, + * null means to treat lhs elements as Comparable. + * @return this - used to chain append calls + * @throws ClassCastException if rhs is not assignment-compatible + * with lhs + * @since 2.0 + */ + public CompareToBuilder append(final Object[] lhs, final Object[] rhs, final Comparator comparator) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i], comparator); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two long arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(long, long)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final long[] lhs, final long[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two int arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(int, int)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final int[] lhs, final int[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two short arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(short, short)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final short[] lhs, final short[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two char arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(char, char)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final char[] lhs, final char[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two byte arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(byte, byte)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final byte[] lhs, final byte[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two double arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(double, double)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final double[] lhs, final double[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two float arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(float, float)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ + public CompareToBuilder append(final float[] lhs, final float[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + if (rhs == null) { + comparison = +1; + return this; + } + if (lhs.length != rhs.length) { + comparison = lhs.length < rhs.length ? -1 : +1; + return this; + } + for (int i = 0; i < lhs.length && comparison == 0; i++) { + append(lhs[i], rhs[i]); + } + return this; + } + + /** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs left-hand array + * @param rhs right-hand array + * @return this - used to chain append calls + */ +/** + *

Appends to the builder the deep comparison of + * two boolean arrays.

+ * + *
    + *
  1. Check if arrays are the same using ==
  2. + *
  3. Check if for null, null is less than non-null
  4. + *
  5. Check array length, a shorter length array is less than a longer length array
  6. + *
  7. Check array contents element by element using {@link #append(boolean, boolean)}
  8. + *
+ * + * @param lhs + * left-hand array + * @param rhs + * right-hand array + * @return this - used to chain append calls + */ +public org.apache.commons.lang3.builder.CompareToBuilder append(final boolean[] lhs, final boolean[] rhs) { + if (comparison != 0) { + return this; + } + if (lhs == rhs) { + return this; + } + if (lhs == null) { + comparison = -1; + return this; + } + { + if (lhs.length != /* NPEX_NULL_EXP */ + rhs.length) { + comparison = (lhs.length < rhs.length) ? -1 : +1; + return this; + } + for (int i = 0; (i < lhs.length) && (comparison == 0); i++) { + append(lhs[i], rhs[i]); + } + return this; + } +} + + //----------------------------------------------------------------------- + /** + * Returns a negative integer, a positive integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result + * @see #build() + */ + public int toComparison() { + return comparison; + } + + /** + * Returns a negative Integer, a positive Integer, or zero as + * the builder has judged the "left-hand" side + * as less than, greater than, or equal to the "right-hand" + * side. + * + * @return final comparison result as an Integer + * @see #toComparison() + * @since 3.0 + */ + @Override + public Integer build() { + return Integer.valueOf(toComparison()); + } +} + diff --git a/Java/commons-lang-CompareToBuilder_990/metadata.json b/Java/commons-lang-CompareToBuilder_990/metadata.json new file mode 100644 index 000000000..6151e84ba --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_990/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-CompareToBuilder_990", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 1009, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder", + "repo": "commons-lang", + "bug_id": "CompareToBuilder_990" + } +} diff --git a/Java/commons-lang-CompareToBuilder_990/npe.json b/Java/commons-lang-CompareToBuilder_990/npe.json new file mode 100644 index 000000000..4ff8fef6b --- /dev/null +++ b/Java/commons-lang-CompareToBuilder_990/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/builder/CompareToBuilder.java", + "line": 1009, + "npe_method": "append", + "deref_field": "rhs", + "npe_class": "CompareToBuilder" +} \ No newline at end of file diff --git a/Java/commons-lang-ConcurrentUtils_109/Dockerfile b/Java/commons-lang-ConcurrentUtils_109/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_109/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-ConcurrentUtils_109/buggy.java b/Java/commons-lang-ConcurrentUtils_109/buggy.java new file mode 100644 index 000000000..0b6300aed --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_109/buggy.java @@ -0,0 +1,405 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.concurrent; + +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.Validate; + +/** + *

+ * An utility class providing functionality related to the {@code + * java.util.concurrent} package. + *

+ * + * @since 3.0 + */ +public class ConcurrentUtils { + + /** + * Private constructor so that no instances can be created. This class + * contains only static utility methods. + */ + private ConcurrentUtils() { + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentException} with the checked cause if + * necessary. This method performs the following checks on the cause of the + * passed in exception: + *
    + *
  • If the passed in exception is null or the cause is + * null, this method returns null.
  • + *
  • If the cause is a runtime exception, it is directly thrown.
  • + *
  • If the cause is an error, it is directly thrown, too.
  • + *
  • In any other case the cause is a checked exception. The method then + * creates a {@link ConcurrentException}, initializes it with the cause, and + * returns it.
  • + *
+ * + * @param ex the exception to be processed + * @return a {@code ConcurrentException} with the checked cause + */ + public static ConcurrentException extractCause(final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentException(ex.getMessage(), ex.getCause()); + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentRuntimeException} with the checked cause if + * necessary. This method works exactly like + * {@link #extractCause(ExecutionException)}. The only difference is that + * the cause of the specified {@code ExecutionException} is extracted as a + * runtime exception. This is an alternative for client code that does not + * want to deal with checked exceptions. + * + * @param ex the exception to be processed + * @return a {@code ConcurrentRuntimeException} with the checked cause + */ + public static ConcurrentRuntimeException extractCauseUnchecked( + final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause()); + } + + /** + * Handles the specified {@code ExecutionException}. This method calls + * {@link #extractCause(ExecutionException)} for obtaining the cause of the + * exception - which might already cause an unchecked exception or an error + * being thrown. If the cause is a checked exception however, it is wrapped + * in a {@code ConcurrentException}, which is thrown. If the passed in + * exception is null or has no cause, the method simply returns + * without throwing an exception. + * + * @param ex the exception to be handled + * @throws ConcurrentException if the cause of the {@code + * ExecutionException} is a checked exception + */ +/** + * Handles the specified {@code ExecutionException}. This method calls + * {@link #extractCause(ExecutionException)} for obtaining the cause of the + * exception - which might already cause an unchecked exception or an error + * being thrown. If the cause is a checked exception however, it is wrapped + * in a {@code ConcurrentException}, which is thrown. If the passed in + * exception is null or has no cause, the method simply returns + * without throwing an exception. + * + * @param ex + * the exception to be handled + * @throws ConcurrentException + * if the cause of the {@code ExecutionException} is a checked exception + */ +public static void handleCause(final java.util.concurrent.ExecutionException ex) throws org.apache.commons.lang3.concurrent.ConcurrentException { + final org.apache.commons.lang3.concurrent.ConcurrentException cex = org.apache.commons.lang3.concurrent.ConcurrentUtils.extractCause(ex); + { + throw /* NPEX_NULL_EXP */ + cex; + } +} + + /** + * Handles the specified {@code ExecutionException} and transforms it into a + * runtime exception. This method works exactly like + * {@link #handleCause(ExecutionException)}, but instead of a + * {@link ConcurrentException} it throws a + * {@link ConcurrentRuntimeException}. This is an alternative for client + * code that does not want to deal with checked exceptions. + * + * @param ex the exception to be handled + * @throws ConcurrentRuntimeException if the cause of the {@code + * ExecutionException} is a checked exception; this exception is then + * wrapped in the thrown runtime exception + */ + public static void handleCauseUnchecked(final ExecutionException ex) { + final ConcurrentRuntimeException crex = extractCauseUnchecked(ex); + + if (crex != null) { + throw crex; + } + } + + /** + * Tests whether the specified {@code Throwable} is a checked exception. If + * not, an exception is thrown. + * + * @param ex the {@code Throwable} to check + * @return a flag whether the passed in exception is a checked exception + * @throws IllegalArgumentException if the {@code Throwable} is not a + * checked exception + */ + static Throwable checkedException(final Throwable ex) { + Validate.isTrue(ex != null && !(ex instanceof RuntimeException) + && !(ex instanceof Error), "Not a checked exception: " + ex); + + return ex; + } + + /** + * Tests whether the cause of the specified {@code ExecutionException} + * should be thrown and does it if necessary. + * + * @param ex the exception in question + */ + private static void throwCause(final ExecutionException ex) { + if (ex.getCause() instanceof RuntimeException) { + throw (RuntimeException) ex.getCause(); + } + + if (ex.getCause() instanceof Error) { + throw (Error) ex.getCause(); + } + } + + //----------------------------------------------------------------------- + /** + * Invokes the specified {@code ConcurrentInitializer} and returns the + * object produced by the initializer. This method just invokes the {@code + * get()} method of the given {@code ConcurrentInitializer}. It is + * null-safe: if the argument is null, result is also + * null. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentException if the {@code ConcurrentInitializer} throws + * an exception + */ + public static T initialize(final ConcurrentInitializer initializer) + throws ConcurrentException { + return initializer != null ? initializer.get() : null; + } + + /** + * Invokes the specified {@code ConcurrentInitializer} and transforms + * occurring exceptions to runtime exceptions. This method works like + * {@link #initialize(ConcurrentInitializer)}, but if the {@code + * ConcurrentInitializer} throws a {@link ConcurrentException}, it is + * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}. + * So client code does not have to deal with checked exceptions. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static T initializeUnchecked(final ConcurrentInitializer initializer) { + try { + return initialize(initializer); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Puts a value in the specified {@code ConcurrentMap} if the key is not yet + * present. This method works similar to the {@code putIfAbsent()} method of + * the {@code ConcurrentMap} interface, but the value returned is different. + * Basically, this method is equivalent to the following code fragment: + *

+ * + *
+     * if (!map.containsKey(key)) {
+     *     map.put(key, value);
+     *     return value;
+     * } else {
+     *     return map.get(key);
+     * }
+     * 
+ * + *

+ * except that the action is performed atomically. So this method always + * returns the value which is stored in the map. + *

+ *

+ * This method is null-safe: It accepts a null map as input + * without throwing an exception. In this case the return value is + * null, too. + *

+ * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param value the value to be added + * @return the value stored in the map after this operation + */ + public static V putIfAbsent(final ConcurrentMap map, final K key, final V value) { + if (map == null) { + return null; + } + + final V result = map.putIfAbsent(key, value); + return result != null ? result : value; + } + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not. This method first checks the presence of the key in the + * given map. If it is already contained, its value is returned. Otherwise + * the {@code get()} method of the passed in {@link ConcurrentInitializer} + * is called. With the resulting object + * {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This + * handles the case that in the meantime another thread has added the key to + * the map. Both the map and the initializer can be null; in this + * case this method simply returns null. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentException if the initializer throws an exception + */ + public static V createIfAbsent(final ConcurrentMap map, final K key, + final ConcurrentInitializer init) throws ConcurrentException { + if (map == null || init == null) { + return null; + } + + final V value = map.get(key); + if (value == null) { + return putIfAbsent(map, key, init.get()); + } + return value; + } + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not, suppressing checked exceptions. This method calls + * {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it + * is caught and re-thrown as a {@link ConcurrentRuntimeException}. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static V createIfAbsentUnchecked(final ConcurrentMap map, + final K key, final ConcurrentInitializer init) { + try { + return createIfAbsent(map, key, init); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Gets an implementation of Future that is immediately done + * and returns the specified constant value. + *

+ *

+ * This can be useful to return a simple constant immediately from the + * concurrent processing, perhaps as part of avoiding nulls. + * A constant future can also be useful in testing. + *

+ * + * @param the type of the value used by this {@code Future} object + * @param value the constant value to return, may be null + * @return an instance of Future that will return the value, never null + */ + public static Future constantFuture(final T value) { + return new ConstantFuture(value); + } + + /** + * A specialized {@code Future} implementation which wraps a constant value. + * @param the type of the value wrapped by this class + */ + static final class ConstantFuture implements Future { + /** The constant value. */ + private final T value; + + /** + * Creates a new instance of {@code ConstantFuture} and initializes it + * with the constant value. + * + * @param value the value (may be null) + */ + ConstantFuture(final T value) { + this.value = value; + } + + /** + * {@inheritDoc} This implementation always returns true because + * the constant object managed by this {@code Future} implementation is + * always available. + */ + @Override + public boolean isDone() { + return true; + } + + /** + * {@inheritDoc} This implementation just returns the constant value. + */ + @Override + public T get() { + return value; + } + + /** + * {@inheritDoc} This implementation just returns the constant value; it + * does not block, therefore the timeout has no meaning. + */ + @Override + public T get(final long timeout, final TimeUnit unit) { + return value; + } + + /** + * {@inheritDoc} This implementation always returns false; there + * is no background process which could be cancelled. + */ + @Override + public boolean isCancelled() { + return false; + } + + /** + * {@inheritDoc} The cancel operation is not supported. This + * implementation always returns false. + */ + @Override + public boolean cancel(final boolean mayInterruptIfRunning) { + return false; + } + } + +} diff --git a/Java/commons-lang-ConcurrentUtils_109/metadata.json b/Java/commons-lang-ConcurrentUtils_109/metadata.json new file mode 100644 index 000000000..4e84deb4e --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_109/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-ConcurrentUtils_109", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 123, + "npe_method": "handleCause", + "deref_field": "cex", + "npe_class": "ConcurrentUtils", + "repo": "commons-lang", + "bug_id": "ConcurrentUtils_109" + } +} diff --git a/Java/commons-lang-ConcurrentUtils_109/npe.json b/Java/commons-lang-ConcurrentUtils_109/npe.json new file mode 100644 index 000000000..c1c110153 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_109/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 123, + "npe_method": "handleCause", + "deref_field": "cex", + "npe_class": "ConcurrentUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-ConcurrentUtils_130/Dockerfile b/Java/commons-lang-ConcurrentUtils_130/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_130/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-ConcurrentUtils_130/buggy.java b/Java/commons-lang-ConcurrentUtils_130/buggy.java new file mode 100644 index 000000000..f169e6e56 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_130/buggy.java @@ -0,0 +1,406 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.concurrent; + +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.Validate; + +/** + *

+ * An utility class providing functionality related to the {@code + * java.util.concurrent} package. + *

+ * + * @since 3.0 + */ +public class ConcurrentUtils { + + /** + * Private constructor so that no instances can be created. This class + * contains only static utility methods. + */ + private ConcurrentUtils() { + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentException} with the checked cause if + * necessary. This method performs the following checks on the cause of the + * passed in exception: + *
    + *
  • If the passed in exception is null or the cause is + * null, this method returns null.
  • + *
  • If the cause is a runtime exception, it is directly thrown.
  • + *
  • If the cause is an error, it is directly thrown, too.
  • + *
  • In any other case the cause is a checked exception. The method then + * creates a {@link ConcurrentException}, initializes it with the cause, and + * returns it.
  • + *
+ * + * @param ex the exception to be processed + * @return a {@code ConcurrentException} with the checked cause + */ + public static ConcurrentException extractCause(final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentException(ex.getMessage(), ex.getCause()); + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentRuntimeException} with the checked cause if + * necessary. This method works exactly like + * {@link #extractCause(ExecutionException)}. The only difference is that + * the cause of the specified {@code ExecutionException} is extracted as a + * runtime exception. This is an alternative for client code that does not + * want to deal with checked exceptions. + * + * @param ex the exception to be processed + * @return a {@code ConcurrentRuntimeException} with the checked cause + */ + public static ConcurrentRuntimeException extractCauseUnchecked( + final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause()); + } + + /** + * Handles the specified {@code ExecutionException}. This method calls + * {@link #extractCause(ExecutionException)} for obtaining the cause of the + * exception - which might already cause an unchecked exception or an error + * being thrown. If the cause is a checked exception however, it is wrapped + * in a {@code ConcurrentException}, which is thrown. If the passed in + * exception is null or has no cause, the method simply returns + * without throwing an exception. + * + * @param ex the exception to be handled + * @throws ConcurrentException if the cause of the {@code + * ExecutionException} is a checked exception + */ + public static void handleCause(final ExecutionException ex) + throws ConcurrentException { + final ConcurrentException cex = extractCause(ex); + + if (cex != null) { + throw cex; + } + } + + /** + * Handles the specified {@code ExecutionException} and transforms it into a + * runtime exception. This method works exactly like + * {@link #handleCause(ExecutionException)}, but instead of a + * {@link ConcurrentException} it throws a + * {@link ConcurrentRuntimeException}. This is an alternative for client + * code that does not want to deal with checked exceptions. + * + * @param ex the exception to be handled + * @throws ConcurrentRuntimeException if the cause of the {@code + * ExecutionException} is a checked exception; this exception is then + * wrapped in the thrown runtime exception + */ +/** + * Handles the specified {@code ExecutionException} and transforms it into a + * runtime exception. This method works exactly like + * {@link #handleCause(ExecutionException)}, but instead of a + * {@link ConcurrentException} it throws a + * {@link ConcurrentRuntimeException}. This is an alternative for client + * code that does not want to deal with checked exceptions. + * + * @param ex + * the exception to be handled + * @throws ConcurrentRuntimeException + * if the cause of the {@code ExecutionException} is a checked exception; this exception is then + * wrapped in the thrown runtime exception + */ +public static void handleCauseUnchecked(final java.util.concurrent.ExecutionException ex) { + final org.apache.commons.lang3.concurrent.ConcurrentRuntimeException crex = org.apache.commons.lang3.concurrent.ConcurrentUtils.extractCauseUnchecked(ex); + { + throw /* NPEX_NULL_EXP */ + crex; + } +} + + /** + * Tests whether the specified {@code Throwable} is a checked exception. If + * not, an exception is thrown. + * + * @param ex the {@code Throwable} to check + * @return a flag whether the passed in exception is a checked exception + * @throws IllegalArgumentException if the {@code Throwable} is not a + * checked exception + */ + static Throwable checkedException(final Throwable ex) { + Validate.isTrue(ex != null && !(ex instanceof RuntimeException) + && !(ex instanceof Error), "Not a checked exception: " + ex); + + return ex; + } + + /** + * Tests whether the cause of the specified {@code ExecutionException} + * should be thrown and does it if necessary. + * + * @param ex the exception in question + */ + private static void throwCause(final ExecutionException ex) { + if (ex.getCause() instanceof RuntimeException) { + throw (RuntimeException) ex.getCause(); + } + + if (ex.getCause() instanceof Error) { + throw (Error) ex.getCause(); + } + } + + //----------------------------------------------------------------------- + /** + * Invokes the specified {@code ConcurrentInitializer} and returns the + * object produced by the initializer. This method just invokes the {@code + * get()} method of the given {@code ConcurrentInitializer}. It is + * null-safe: if the argument is null, result is also + * null. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentException if the {@code ConcurrentInitializer} throws + * an exception + */ + public static T initialize(final ConcurrentInitializer initializer) + throws ConcurrentException { + return initializer != null ? initializer.get() : null; + } + + /** + * Invokes the specified {@code ConcurrentInitializer} and transforms + * occurring exceptions to runtime exceptions. This method works like + * {@link #initialize(ConcurrentInitializer)}, but if the {@code + * ConcurrentInitializer} throws a {@link ConcurrentException}, it is + * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}. + * So client code does not have to deal with checked exceptions. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static T initializeUnchecked(final ConcurrentInitializer initializer) { + try { + return initialize(initializer); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Puts a value in the specified {@code ConcurrentMap} if the key is not yet + * present. This method works similar to the {@code putIfAbsent()} method of + * the {@code ConcurrentMap} interface, but the value returned is different. + * Basically, this method is equivalent to the following code fragment: + *

+ * + *
+     * if (!map.containsKey(key)) {
+     *     map.put(key, value);
+     *     return value;
+     * } else {
+     *     return map.get(key);
+     * }
+     * 
+ * + *

+ * except that the action is performed atomically. So this method always + * returns the value which is stored in the map. + *

+ *

+ * This method is null-safe: It accepts a null map as input + * without throwing an exception. In this case the return value is + * null, too. + *

+ * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param value the value to be added + * @return the value stored in the map after this operation + */ + public static V putIfAbsent(final ConcurrentMap map, final K key, final V value) { + if (map == null) { + return null; + } + + final V result = map.putIfAbsent(key, value); + return result != null ? result : value; + } + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not. This method first checks the presence of the key in the + * given map. If it is already contained, its value is returned. Otherwise + * the {@code get()} method of the passed in {@link ConcurrentInitializer} + * is called. With the resulting object + * {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This + * handles the case that in the meantime another thread has added the key to + * the map. Both the map and the initializer can be null; in this + * case this method simply returns null. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentException if the initializer throws an exception + */ + public static V createIfAbsent(final ConcurrentMap map, final K key, + final ConcurrentInitializer init) throws ConcurrentException { + if (map == null || init == null) { + return null; + } + + final V value = map.get(key); + if (value == null) { + return putIfAbsent(map, key, init.get()); + } + return value; + } + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not, suppressing checked exceptions. This method calls + * {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it + * is caught and re-thrown as a {@link ConcurrentRuntimeException}. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static V createIfAbsentUnchecked(final ConcurrentMap map, + final K key, final ConcurrentInitializer init) { + try { + return createIfAbsent(map, key, init); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Gets an implementation of Future that is immediately done + * and returns the specified constant value. + *

+ *

+ * This can be useful to return a simple constant immediately from the + * concurrent processing, perhaps as part of avoiding nulls. + * A constant future can also be useful in testing. + *

+ * + * @param the type of the value used by this {@code Future} object + * @param value the constant value to return, may be null + * @return an instance of Future that will return the value, never null + */ + public static Future constantFuture(final T value) { + return new ConstantFuture(value); + } + + /** + * A specialized {@code Future} implementation which wraps a constant value. + * @param the type of the value wrapped by this class + */ + static final class ConstantFuture implements Future { + /** The constant value. */ + private final T value; + + /** + * Creates a new instance of {@code ConstantFuture} and initializes it + * with the constant value. + * + * @param value the value (may be null) + */ + ConstantFuture(final T value) { + this.value = value; + } + + /** + * {@inheritDoc} This implementation always returns true because + * the constant object managed by this {@code Future} implementation is + * always available. + */ + @Override + public boolean isDone() { + return true; + } + + /** + * {@inheritDoc} This implementation just returns the constant value. + */ + @Override + public T get() { + return value; + } + + /** + * {@inheritDoc} This implementation just returns the constant value; it + * does not block, therefore the timeout has no meaning. + */ + @Override + public T get(final long timeout, final TimeUnit unit) { + return value; + } + + /** + * {@inheritDoc} This implementation always returns false; there + * is no background process which could be cancelled. + */ + @Override + public boolean isCancelled() { + return false; + } + + /** + * {@inheritDoc} The cancel operation is not supported. This + * implementation always returns false. + */ + @Override + public boolean cancel(final boolean mayInterruptIfRunning) { + return false; + } + } + +} diff --git a/Java/commons-lang-ConcurrentUtils_130/metadata.json b/Java/commons-lang-ConcurrentUtils_130/metadata.json new file mode 100644 index 000000000..c90b71d7d --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_130/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-ConcurrentUtils_130", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 145, + "npe_method": "handleCauseUnchecked", + "deref_field": "crex", + "npe_class": "ConcurrentUtils", + "repo": "commons-lang", + "bug_id": "ConcurrentUtils_130" + } +} diff --git a/Java/commons-lang-ConcurrentUtils_130/npe.json b/Java/commons-lang-ConcurrentUtils_130/npe.json new file mode 100644 index 000000000..d5f849fab --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_130/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 145, + "npe_method": "handleCauseUnchecked", + "deref_field": "crex", + "npe_class": "ConcurrentUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-ConcurrentUtils_183/Dockerfile b/Java/commons-lang-ConcurrentUtils_183/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_183/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-ConcurrentUtils_183/buggy.java b/Java/commons-lang-ConcurrentUtils_183/buggy.java new file mode 100644 index 000000000..01e8c4633 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_183/buggy.java @@ -0,0 +1,408 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.concurrent; + +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.Validate; + +/** + *

+ * An utility class providing functionality related to the {@code + * java.util.concurrent} package. + *

+ * + * @since 3.0 + */ +public class ConcurrentUtils { + + /** + * Private constructor so that no instances can be created. This class + * contains only static utility methods. + */ + private ConcurrentUtils() { + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentException} with the checked cause if + * necessary. This method performs the following checks on the cause of the + * passed in exception: + *
    + *
  • If the passed in exception is null or the cause is + * null, this method returns null.
  • + *
  • If the cause is a runtime exception, it is directly thrown.
  • + *
  • If the cause is an error, it is directly thrown, too.
  • + *
  • In any other case the cause is a checked exception. The method then + * creates a {@link ConcurrentException}, initializes it with the cause, and + * returns it.
  • + *
+ * + * @param ex the exception to be processed + * @return a {@code ConcurrentException} with the checked cause + */ + public static ConcurrentException extractCause(final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentException(ex.getMessage(), ex.getCause()); + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentRuntimeException} with the checked cause if + * necessary. This method works exactly like + * {@link #extractCause(ExecutionException)}. The only difference is that + * the cause of the specified {@code ExecutionException} is extracted as a + * runtime exception. This is an alternative for client code that does not + * want to deal with checked exceptions. + * + * @param ex the exception to be processed + * @return a {@code ConcurrentRuntimeException} with the checked cause + */ + public static ConcurrentRuntimeException extractCauseUnchecked( + final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause()); + } + + /** + * Handles the specified {@code ExecutionException}. This method calls + * {@link #extractCause(ExecutionException)} for obtaining the cause of the + * exception - which might already cause an unchecked exception or an error + * being thrown. If the cause is a checked exception however, it is wrapped + * in a {@code ConcurrentException}, which is thrown. If the passed in + * exception is null or has no cause, the method simply returns + * without throwing an exception. + * + * @param ex the exception to be handled + * @throws ConcurrentException if the cause of the {@code + * ExecutionException} is a checked exception + */ + public static void handleCause(final ExecutionException ex) + throws ConcurrentException { + final ConcurrentException cex = extractCause(ex); + + if (cex != null) { + throw cex; + } + } + + /** + * Handles the specified {@code ExecutionException} and transforms it into a + * runtime exception. This method works exactly like + * {@link #handleCause(ExecutionException)}, but instead of a + * {@link ConcurrentException} it throws a + * {@link ConcurrentRuntimeException}. This is an alternative for client + * code that does not want to deal with checked exceptions. + * + * @param ex the exception to be handled + * @throws ConcurrentRuntimeException if the cause of the {@code + * ExecutionException} is a checked exception; this exception is then + * wrapped in the thrown runtime exception + */ + public static void handleCauseUnchecked(final ExecutionException ex) { + final ConcurrentRuntimeException crex = extractCauseUnchecked(ex); + + if (crex != null) { + throw crex; + } + } + + /** + * Tests whether the specified {@code Throwable} is a checked exception. If + * not, an exception is thrown. + * + * @param ex the {@code Throwable} to check + * @return a flag whether the passed in exception is a checked exception + * @throws IllegalArgumentException if the {@code Throwable} is not a + * checked exception + */ + static Throwable checkedException(final Throwable ex) { + Validate.isTrue(ex != null && !(ex instanceof RuntimeException) + && !(ex instanceof Error), "Not a checked exception: " + ex); + + return ex; + } + + /** + * Tests whether the cause of the specified {@code ExecutionException} + * should be thrown and does it if necessary. + * + * @param ex the exception in question + */ + private static void throwCause(final ExecutionException ex) { + if (ex.getCause() instanceof RuntimeException) { + throw (RuntimeException) ex.getCause(); + } + + if (ex.getCause() instanceof Error) { + throw (Error) ex.getCause(); + } + } + + //----------------------------------------------------------------------- + /** + * Invokes the specified {@code ConcurrentInitializer} and returns the + * object produced by the initializer. This method just invokes the {@code + * get()} method of the given {@code ConcurrentInitializer}. It is + * null-safe: if the argument is null, result is also + * null. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentException if the {@code ConcurrentInitializer} throws + * an exception + */ +// ----------------------------------------------------------------------- +/** + * Invokes the specified {@code ConcurrentInitializer} and returns the + * object produced by the initializer. This method just invokes the {@code get()} method of the given {@code ConcurrentInitializer}. It is + * null-safe: if the argument is null, result is also + * null. + * + * @param + * the type of the object produced by the initializer + * @param initializer + * the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentException + * if the {@code ConcurrentInitializer} throws + * an exception + */ +public static T initialize(final org.apache.commons.lang3.concurrent.ConcurrentInitializer initializer) throws org.apache.commons.lang3.concurrent.ConcurrentException { + return /* NPEX_NULL_EXP */ + initializer.get(); +} + + /** + * Invokes the specified {@code ConcurrentInitializer} and transforms + * occurring exceptions to runtime exceptions. This method works like + * {@link #initialize(ConcurrentInitializer)}, but if the {@code + * ConcurrentInitializer} throws a {@link ConcurrentException}, it is + * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}. + * So client code does not have to deal with checked exceptions. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static T initializeUnchecked(final ConcurrentInitializer initializer) { + try { + return initialize(initializer); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Puts a value in the specified {@code ConcurrentMap} if the key is not yet + * present. This method works similar to the {@code putIfAbsent()} method of + * the {@code ConcurrentMap} interface, but the value returned is different. + * Basically, this method is equivalent to the following code fragment: + *

+ * + *
+     * if (!map.containsKey(key)) {
+     *     map.put(key, value);
+     *     return value;
+     * } else {
+     *     return map.get(key);
+     * }
+     * 
+ * + *

+ * except that the action is performed atomically. So this method always + * returns the value which is stored in the map. + *

+ *

+ * This method is null-safe: It accepts a null map as input + * without throwing an exception. In this case the return value is + * null, too. + *

+ * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param value the value to be added + * @return the value stored in the map after this operation + */ + public static V putIfAbsent(final ConcurrentMap map, final K key, final V value) { + if (map == null) { + return null; + } + + final V result = map.putIfAbsent(key, value); + return result != null ? result : value; + } + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not. This method first checks the presence of the key in the + * given map. If it is already contained, its value is returned. Otherwise + * the {@code get()} method of the passed in {@link ConcurrentInitializer} + * is called. With the resulting object + * {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This + * handles the case that in the meantime another thread has added the key to + * the map. Both the map and the initializer can be null; in this + * case this method simply returns null. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentException if the initializer throws an exception + */ + public static V createIfAbsent(final ConcurrentMap map, final K key, + final ConcurrentInitializer init) throws ConcurrentException { + if (map == null || init == null) { + return null; + } + + final V value = map.get(key); + if (value == null) { + return putIfAbsent(map, key, init.get()); + } + return value; + } + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not, suppressing checked exceptions. This method calls + * {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it + * is caught and re-thrown as a {@link ConcurrentRuntimeException}. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static V createIfAbsentUnchecked(final ConcurrentMap map, + final K key, final ConcurrentInitializer init) { + try { + return createIfAbsent(map, key, init); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Gets an implementation of Future that is immediately done + * and returns the specified constant value. + *

+ *

+ * This can be useful to return a simple constant immediately from the + * concurrent processing, perhaps as part of avoiding nulls. + * A constant future can also be useful in testing. + *

+ * + * @param the type of the value used by this {@code Future} object + * @param value the constant value to return, may be null + * @return an instance of Future that will return the value, never null + */ + public static Future constantFuture(final T value) { + return new ConstantFuture(value); + } + + /** + * A specialized {@code Future} implementation which wraps a constant value. + * @param the type of the value wrapped by this class + */ + static final class ConstantFuture implements Future { + /** The constant value. */ + private final T value; + + /** + * Creates a new instance of {@code ConstantFuture} and initializes it + * with the constant value. + * + * @param value the value (may be null) + */ + ConstantFuture(final T value) { + this.value = value; + } + + /** + * {@inheritDoc} This implementation always returns true because + * the constant object managed by this {@code Future} implementation is + * always available. + */ + @Override + public boolean isDone() { + return true; + } + + /** + * {@inheritDoc} This implementation just returns the constant value. + */ + @Override + public T get() { + return value; + } + + /** + * {@inheritDoc} This implementation just returns the constant value; it + * does not block, therefore the timeout has no meaning. + */ + @Override + public T get(final long timeout, final TimeUnit unit) { + return value; + } + + /** + * {@inheritDoc} This implementation always returns false; there + * is no background process which could be cancelled. + */ + @Override + public boolean isCancelled() { + return false; + } + + /** + * {@inheritDoc} The cancel operation is not supported. This + * implementation always returns false. + */ + @Override + public boolean cancel(final boolean mayInterruptIfRunning) { + return false; + } + } + +} diff --git a/Java/commons-lang-ConcurrentUtils_183/metadata.json b/Java/commons-lang-ConcurrentUtils_183/metadata.json new file mode 100644 index 000000000..168ab64e9 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_183/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-ConcurrentUtils_183", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 199, + "npe_method": "initialize", + "deref_field": "initializer", + "npe_class": "ConcurrentUtils", + "repo": "commons-lang", + "bug_id": "ConcurrentUtils_183" + } +} diff --git a/Java/commons-lang-ConcurrentUtils_183/npe.json b/Java/commons-lang-ConcurrentUtils_183/npe.json new file mode 100644 index 000000000..01837640f --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_183/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 199, + "npe_method": "initialize", + "deref_field": "initializer", + "npe_class": "ConcurrentUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-ConcurrentUtils_243/Dockerfile b/Java/commons-lang-ConcurrentUtils_243/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_243/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-ConcurrentUtils_243/buggy.java b/Java/commons-lang-ConcurrentUtils_243/buggy.java new file mode 100644 index 000000000..36c31b327 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_243/buggy.java @@ -0,0 +1,431 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.concurrent; + +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.Validate; + +/** + *

+ * An utility class providing functionality related to the {@code + * java.util.concurrent} package. + *

+ * + * @since 3.0 + */ +public class ConcurrentUtils { + + /** + * Private constructor so that no instances can be created. This class + * contains only static utility methods. + */ + private ConcurrentUtils() { + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentException} with the checked cause if + * necessary. This method performs the following checks on the cause of the + * passed in exception: + *
    + *
  • If the passed in exception is null or the cause is + * null, this method returns null.
  • + *
  • If the cause is a runtime exception, it is directly thrown.
  • + *
  • If the cause is an error, it is directly thrown, too.
  • + *
  • In any other case the cause is a checked exception. The method then + * creates a {@link ConcurrentException}, initializes it with the cause, and + * returns it.
  • + *
+ * + * @param ex the exception to be processed + * @return a {@code ConcurrentException} with the checked cause + */ + public static ConcurrentException extractCause(final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentException(ex.getMessage(), ex.getCause()); + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentRuntimeException} with the checked cause if + * necessary. This method works exactly like + * {@link #extractCause(ExecutionException)}. The only difference is that + * the cause of the specified {@code ExecutionException} is extracted as a + * runtime exception. This is an alternative for client code that does not + * want to deal with checked exceptions. + * + * @param ex the exception to be processed + * @return a {@code ConcurrentRuntimeException} with the checked cause + */ + public static ConcurrentRuntimeException extractCauseUnchecked( + final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause()); + } + + /** + * Handles the specified {@code ExecutionException}. This method calls + * {@link #extractCause(ExecutionException)} for obtaining the cause of the + * exception - which might already cause an unchecked exception or an error + * being thrown. If the cause is a checked exception however, it is wrapped + * in a {@code ConcurrentException}, which is thrown. If the passed in + * exception is null or has no cause, the method simply returns + * without throwing an exception. + * + * @param ex the exception to be handled + * @throws ConcurrentException if the cause of the {@code + * ExecutionException} is a checked exception + */ + public static void handleCause(final ExecutionException ex) + throws ConcurrentException { + final ConcurrentException cex = extractCause(ex); + + if (cex != null) { + throw cex; + } + } + + /** + * Handles the specified {@code ExecutionException} and transforms it into a + * runtime exception. This method works exactly like + * {@link #handleCause(ExecutionException)}, but instead of a + * {@link ConcurrentException} it throws a + * {@link ConcurrentRuntimeException}. This is an alternative for client + * code that does not want to deal with checked exceptions. + * + * @param ex the exception to be handled + * @throws ConcurrentRuntimeException if the cause of the {@code + * ExecutionException} is a checked exception; this exception is then + * wrapped in the thrown runtime exception + */ + public static void handleCauseUnchecked(final ExecutionException ex) { + final ConcurrentRuntimeException crex = extractCauseUnchecked(ex); + + if (crex != null) { + throw crex; + } + } + + /** + * Tests whether the specified {@code Throwable} is a checked exception. If + * not, an exception is thrown. + * + * @param ex the {@code Throwable} to check + * @return a flag whether the passed in exception is a checked exception + * @throws IllegalArgumentException if the {@code Throwable} is not a + * checked exception + */ + static Throwable checkedException(final Throwable ex) { + Validate.isTrue(ex != null && !(ex instanceof RuntimeException) + && !(ex instanceof Error), "Not a checked exception: " + ex); + + return ex; + } + + /** + * Tests whether the cause of the specified {@code ExecutionException} + * should be thrown and does it if necessary. + * + * @param ex the exception in question + */ + private static void throwCause(final ExecutionException ex) { + if (ex.getCause() instanceof RuntimeException) { + throw (RuntimeException) ex.getCause(); + } + + if (ex.getCause() instanceof Error) { + throw (Error) ex.getCause(); + } + } + + //----------------------------------------------------------------------- + /** + * Invokes the specified {@code ConcurrentInitializer} and returns the + * object produced by the initializer. This method just invokes the {@code + * get()} method of the given {@code ConcurrentInitializer}. It is + * null-safe: if the argument is null, result is also + * null. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentException if the {@code ConcurrentInitializer} throws + * an exception + */ + public static T initialize(final ConcurrentInitializer initializer) + throws ConcurrentException { + return initializer != null ? initializer.get() : null; + } + + /** + * Invokes the specified {@code ConcurrentInitializer} and transforms + * occurring exceptions to runtime exceptions. This method works like + * {@link #initialize(ConcurrentInitializer)}, but if the {@code + * ConcurrentInitializer} throws a {@link ConcurrentException}, it is + * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}. + * So client code does not have to deal with checked exceptions. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static T initializeUnchecked(final ConcurrentInitializer initializer) { + try { + return initialize(initializer); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Puts a value in the specified {@code ConcurrentMap} if the key is not yet + * present. This method works similar to the {@code putIfAbsent()} method of + * the {@code ConcurrentMap} interface, but the value returned is different. + * Basically, this method is equivalent to the following code fragment: + *

+ * + *
+     * if (!map.containsKey(key)) {
+     *     map.put(key, value);
+     *     return value;
+     * } else {
+     *     return map.get(key);
+     * }
+     * 
+ * + *

+ * except that the action is performed atomically. So this method always + * returns the value which is stored in the map. + *

+ *

+ * This method is null-safe: It accepts a null map as input + * without throwing an exception. In this case the return value is + * null, too. + *

+ * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param value the value to be added + * @return the value stored in the map after this operation + */ +// ----------------------------------------------------------------------- +/** + *

+ * Puts a value in the specified {@code ConcurrentMap} if the key is not yet + * present. This method works similar to the {@code putIfAbsent()} method of + * the {@code ConcurrentMap} interface, but the value returned is different. + * Basically, this method is equivalent to the following code fragment: + *

+ * + *
+ * if (!map.containsKey(key)) {
+ * map.put(key, value);
+ * return value;
+ * } else {
+ * return map.get(key);
+ * }
+ * 
+ * + *

+ * except that the action is performed atomically. So this method always + * returns the value which is stored in the map. + *

+ *

+ * This method is null-safe: It accepts a null map as input + * without throwing an exception. In this case the return value is + * null, too. + *

+ * + * @param + * the type of the keys of the map + * @param + * the type of the values of the map + * @param map + * the map to be modified + * @param key + * the key of the value to be added + * @param value + * the value to be added + * @return the value stored in the map after this operation + */ +public static V putIfAbsent(final java.util.concurrent.ConcurrentMap map, final K key, final V value) { + { + final V result = /* NPEX_NULL_EXP */ + map.putIfAbsent(key, value); + return result != null ? result : value; + } +} + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not. This method first checks the presence of the key in the + * given map. If it is already contained, its value is returned. Otherwise + * the {@code get()} method of the passed in {@link ConcurrentInitializer} + * is called. With the resulting object + * {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This + * handles the case that in the meantime another thread has added the key to + * the map. Both the map and the initializer can be null; in this + * case this method simply returns null. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentException if the initializer throws an exception + */ + public static V createIfAbsent(final ConcurrentMap map, final K key, + final ConcurrentInitializer init) throws ConcurrentException { + if (map == null || init == null) { + return null; + } + + final V value = map.get(key); + if (value == null) { + return putIfAbsent(map, key, init.get()); + } + return value; + } + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not, suppressing checked exceptions. This method calls + * {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it + * is caught and re-thrown as a {@link ConcurrentRuntimeException}. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static V createIfAbsentUnchecked(final ConcurrentMap map, + final K key, final ConcurrentInitializer init) { + try { + return createIfAbsent(map, key, init); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Gets an implementation of Future that is immediately done + * and returns the specified constant value. + *

+ *

+ * This can be useful to return a simple constant immediately from the + * concurrent processing, perhaps as part of avoiding nulls. + * A constant future can also be useful in testing. + *

+ * + * @param the type of the value used by this {@code Future} object + * @param value the constant value to return, may be null + * @return an instance of Future that will return the value, never null + */ + public static Future constantFuture(final T value) { + return new ConstantFuture(value); + } + + /** + * A specialized {@code Future} implementation which wraps a constant value. + * @param the type of the value wrapped by this class + */ + static final class ConstantFuture implements Future { + /** The constant value. */ + private final T value; + + /** + * Creates a new instance of {@code ConstantFuture} and initializes it + * with the constant value. + * + * @param value the value (may be null) + */ + ConstantFuture(final T value) { + this.value = value; + } + + /** + * {@inheritDoc} This implementation always returns true because + * the constant object managed by this {@code Future} implementation is + * always available. + */ + @Override + public boolean isDone() { + return true; + } + + /** + * {@inheritDoc} This implementation just returns the constant value. + */ + @Override + public T get() { + return value; + } + + /** + * {@inheritDoc} This implementation just returns the constant value; it + * does not block, therefore the timeout has no meaning. + */ + @Override + public T get(final long timeout, final TimeUnit unit) { + return value; + } + + /** + * {@inheritDoc} This implementation always returns false; there + * is no background process which could be cancelled. + */ + @Override + public boolean isCancelled() { + return false; + } + + /** + * {@inheritDoc} The cancel operation is not supported. This + * implementation always returns false. + */ + @Override + public boolean cancel(final boolean mayInterruptIfRunning) { + return false; + } + } + +} diff --git a/Java/commons-lang-ConcurrentUtils_243/metadata.json b/Java/commons-lang-ConcurrentUtils_243/metadata.json new file mode 100644 index 000000000..bb4b45936 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_243/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-ConcurrentUtils_243", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 285, + "npe_method": "putIfAbsent", + "deref_field": "map", + "npe_class": "ConcurrentUtils", + "repo": "commons-lang", + "bug_id": "ConcurrentUtils_243" + } +} diff --git a/Java/commons-lang-ConcurrentUtils_243/npe.json b/Java/commons-lang-ConcurrentUtils_243/npe.json new file mode 100644 index 000000000..4cd982b6f --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_243/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 285, + "npe_method": "putIfAbsent", + "deref_field": "map", + "npe_class": "ConcurrentUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-ConcurrentUtils_248/Dockerfile b/Java/commons-lang-ConcurrentUtils_248/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_248/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-ConcurrentUtils_248/buggy.java b/Java/commons-lang-ConcurrentUtils_248/buggy.java new file mode 100644 index 000000000..79dee5ab6 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_248/buggy.java @@ -0,0 +1,432 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.concurrent; + +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.Validate; + +/** + *

+ * An utility class providing functionality related to the {@code + * java.util.concurrent} package. + *

+ * + * @since 3.0 + */ +public class ConcurrentUtils { + + /** + * Private constructor so that no instances can be created. This class + * contains only static utility methods. + */ + private ConcurrentUtils() { + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentException} with the checked cause if + * necessary. This method performs the following checks on the cause of the + * passed in exception: + *
    + *
  • If the passed in exception is null or the cause is + * null, this method returns null.
  • + *
  • If the cause is a runtime exception, it is directly thrown.
  • + *
  • If the cause is an error, it is directly thrown, too.
  • + *
  • In any other case the cause is a checked exception. The method then + * creates a {@link ConcurrentException}, initializes it with the cause, and + * returns it.
  • + *
+ * + * @param ex the exception to be processed + * @return a {@code ConcurrentException} with the checked cause + */ + public static ConcurrentException extractCause(final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentException(ex.getMessage(), ex.getCause()); + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentRuntimeException} with the checked cause if + * necessary. This method works exactly like + * {@link #extractCause(ExecutionException)}. The only difference is that + * the cause of the specified {@code ExecutionException} is extracted as a + * runtime exception. This is an alternative for client code that does not + * want to deal with checked exceptions. + * + * @param ex the exception to be processed + * @return a {@code ConcurrentRuntimeException} with the checked cause + */ + public static ConcurrentRuntimeException extractCauseUnchecked( + final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause()); + } + + /** + * Handles the specified {@code ExecutionException}. This method calls + * {@link #extractCause(ExecutionException)} for obtaining the cause of the + * exception - which might already cause an unchecked exception or an error + * being thrown. If the cause is a checked exception however, it is wrapped + * in a {@code ConcurrentException}, which is thrown. If the passed in + * exception is null or has no cause, the method simply returns + * without throwing an exception. + * + * @param ex the exception to be handled + * @throws ConcurrentException if the cause of the {@code + * ExecutionException} is a checked exception + */ + public static void handleCause(final ExecutionException ex) + throws ConcurrentException { + final ConcurrentException cex = extractCause(ex); + + if (cex != null) { + throw cex; + } + } + + /** + * Handles the specified {@code ExecutionException} and transforms it into a + * runtime exception. This method works exactly like + * {@link #handleCause(ExecutionException)}, but instead of a + * {@link ConcurrentException} it throws a + * {@link ConcurrentRuntimeException}. This is an alternative for client + * code that does not want to deal with checked exceptions. + * + * @param ex the exception to be handled + * @throws ConcurrentRuntimeException if the cause of the {@code + * ExecutionException} is a checked exception; this exception is then + * wrapped in the thrown runtime exception + */ + public static void handleCauseUnchecked(final ExecutionException ex) { + final ConcurrentRuntimeException crex = extractCauseUnchecked(ex); + + if (crex != null) { + throw crex; + } + } + + /** + * Tests whether the specified {@code Throwable} is a checked exception. If + * not, an exception is thrown. + * + * @param ex the {@code Throwable} to check + * @return a flag whether the passed in exception is a checked exception + * @throws IllegalArgumentException if the {@code Throwable} is not a + * checked exception + */ + static Throwable checkedException(final Throwable ex) { + Validate.isTrue(ex != null && !(ex instanceof RuntimeException) + && !(ex instanceof Error), "Not a checked exception: " + ex); + + return ex; + } + + /** + * Tests whether the cause of the specified {@code ExecutionException} + * should be thrown and does it if necessary. + * + * @param ex the exception in question + */ + private static void throwCause(final ExecutionException ex) { + if (ex.getCause() instanceof RuntimeException) { + throw (RuntimeException) ex.getCause(); + } + + if (ex.getCause() instanceof Error) { + throw (Error) ex.getCause(); + } + } + + //----------------------------------------------------------------------- + /** + * Invokes the specified {@code ConcurrentInitializer} and returns the + * object produced by the initializer. This method just invokes the {@code + * get()} method of the given {@code ConcurrentInitializer}. It is + * null-safe: if the argument is null, result is also + * null. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentException if the {@code ConcurrentInitializer} throws + * an exception + */ + public static T initialize(final ConcurrentInitializer initializer) + throws ConcurrentException { + return initializer != null ? initializer.get() : null; + } + + /** + * Invokes the specified {@code ConcurrentInitializer} and transforms + * occurring exceptions to runtime exceptions. This method works like + * {@link #initialize(ConcurrentInitializer)}, but if the {@code + * ConcurrentInitializer} throws a {@link ConcurrentException}, it is + * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}. + * So client code does not have to deal with checked exceptions. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static T initializeUnchecked(final ConcurrentInitializer initializer) { + try { + return initialize(initializer); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Puts a value in the specified {@code ConcurrentMap} if the key is not yet + * present. This method works similar to the {@code putIfAbsent()} method of + * the {@code ConcurrentMap} interface, but the value returned is different. + * Basically, this method is equivalent to the following code fragment: + *

+ * + *
+     * if (!map.containsKey(key)) {
+     *     map.put(key, value);
+     *     return value;
+     * } else {
+     *     return map.get(key);
+     * }
+     * 
+ * + *

+ * except that the action is performed atomically. So this method always + * returns the value which is stored in the map. + *

+ *

+ * This method is null-safe: It accepts a null map as input + * without throwing an exception. In this case the return value is + * null, too. + *

+ * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param value the value to be added + * @return the value stored in the map after this operation + */ +// ----------------------------------------------------------------------- +/** + *

+ * Puts a value in the specified {@code ConcurrentMap} if the key is not yet + * present. This method works similar to the {@code putIfAbsent()} method of + * the {@code ConcurrentMap} interface, but the value returned is different. + * Basically, this method is equivalent to the following code fragment: + *

+ * + *
+ * if (!map.containsKey(key)) {
+ * map.put(key, value);
+ * return value;
+ * } else {
+ * return map.get(key);
+ * }
+ * 
+ * + *

+ * except that the action is performed atomically. So this method always + * returns the value which is stored in the map. + *

+ *

+ * This method is null-safe: It accepts a null map as input + * without throwing an exception. In this case the return value is + * null, too. + *

+ * + * @param + * the type of the keys of the map + * @param + * the type of the values of the map + * @param map + * the map to be modified + * @param key + * the key of the value to be added + * @param value + * the value to be added + * @return the value stored in the map after this operation + */ +public static V putIfAbsent(final java.util.concurrent.ConcurrentMap map, final K key, final V value) { + if (map == null) { + return null; + } + final V result = map.putIfAbsent(key, value); + return /* NPEX_NULL_EXP */ + result; +} + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not. This method first checks the presence of the key in the + * given map. If it is already contained, its value is returned. Otherwise + * the {@code get()} method of the passed in {@link ConcurrentInitializer} + * is called. With the resulting object + * {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This + * handles the case that in the meantime another thread has added the key to + * the map. Both the map and the initializer can be null; in this + * case this method simply returns null. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentException if the initializer throws an exception + */ + public static V createIfAbsent(final ConcurrentMap map, final K key, + final ConcurrentInitializer init) throws ConcurrentException { + if (map == null || init == null) { + return null; + } + + final V value = map.get(key); + if (value == null) { + return putIfAbsent(map, key, init.get()); + } + return value; + } + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not, suppressing checked exceptions. This method calls + * {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it + * is caught and re-thrown as a {@link ConcurrentRuntimeException}. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static V createIfAbsentUnchecked(final ConcurrentMap map, + final K key, final ConcurrentInitializer init) { + try { + return createIfAbsent(map, key, init); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Gets an implementation of Future that is immediately done + * and returns the specified constant value. + *

+ *

+ * This can be useful to return a simple constant immediately from the + * concurrent processing, perhaps as part of avoiding nulls. + * A constant future can also be useful in testing. + *

+ * + * @param the type of the value used by this {@code Future} object + * @param value the constant value to return, may be null + * @return an instance of Future that will return the value, never null + */ + public static Future constantFuture(final T value) { + return new ConstantFuture(value); + } + + /** + * A specialized {@code Future} implementation which wraps a constant value. + * @param the type of the value wrapped by this class + */ + static final class ConstantFuture implements Future { + /** The constant value. */ + private final T value; + + /** + * Creates a new instance of {@code ConstantFuture} and initializes it + * with the constant value. + * + * @param value the value (may be null) + */ + ConstantFuture(final T value) { + this.value = value; + } + + /** + * {@inheritDoc} This implementation always returns true because + * the constant object managed by this {@code Future} implementation is + * always available. + */ + @Override + public boolean isDone() { + return true; + } + + /** + * {@inheritDoc} This implementation just returns the constant value. + */ + @Override + public T get() { + return value; + } + + /** + * {@inheritDoc} This implementation just returns the constant value; it + * does not block, therefore the timeout has no meaning. + */ + @Override + public T get(final long timeout, final TimeUnit unit) { + return value; + } + + /** + * {@inheritDoc} This implementation always returns false; there + * is no background process which could be cancelled. + */ + @Override + public boolean isCancelled() { + return false; + } + + /** + * {@inheritDoc} The cancel operation is not supported. This + * implementation always returns false. + */ + @Override + public boolean cancel(final boolean mayInterruptIfRunning) { + return false; + } + } + +} diff --git a/Java/commons-lang-ConcurrentUtils_248/metadata.json b/Java/commons-lang-ConcurrentUtils_248/metadata.json new file mode 100644 index 000000000..cdc0f36d4 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_248/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-ConcurrentUtils_248", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 288, + "npe_method": "putIfAbsent", + "deref_field": "result", + "npe_class": "ConcurrentUtils", + "repo": "commons-lang", + "bug_id": "ConcurrentUtils_248" + } +} diff --git a/Java/commons-lang-ConcurrentUtils_248/npe.json b/Java/commons-lang-ConcurrentUtils_248/npe.json new file mode 100644 index 000000000..b43252e65 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_248/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 288, + "npe_method": "putIfAbsent", + "deref_field": "result", + "npe_class": "ConcurrentUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-ConcurrentUtils_278/Dockerfile b/Java/commons-lang-ConcurrentUtils_278/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_278/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-ConcurrentUtils_278/buggy.java b/Java/commons-lang-ConcurrentUtils_278/buggy.java new file mode 100644 index 000000000..ddba94884 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_278/buggy.java @@ -0,0 +1,416 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.concurrent; + +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; + +import org.apache.commons.lang3.Validate; + +/** + *

+ * An utility class providing functionality related to the {@code + * java.util.concurrent} package. + *

+ * + * @since 3.0 + */ +public class ConcurrentUtils { + + /** + * Private constructor so that no instances can be created. This class + * contains only static utility methods. + */ + private ConcurrentUtils() { + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentException} with the checked cause if + * necessary. This method performs the following checks on the cause of the + * passed in exception: + *
    + *
  • If the passed in exception is null or the cause is + * null, this method returns null.
  • + *
  • If the cause is a runtime exception, it is directly thrown.
  • + *
  • If the cause is an error, it is directly thrown, too.
  • + *
  • In any other case the cause is a checked exception. The method then + * creates a {@link ConcurrentException}, initializes it with the cause, and + * returns it.
  • + *
+ * + * @param ex the exception to be processed + * @return a {@code ConcurrentException} with the checked cause + */ + public static ConcurrentException extractCause(final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentException(ex.getMessage(), ex.getCause()); + } + + /** + * Inspects the cause of the specified {@code ExecutionException} and + * creates a {@code ConcurrentRuntimeException} with the checked cause if + * necessary. This method works exactly like + * {@link #extractCause(ExecutionException)}. The only difference is that + * the cause of the specified {@code ExecutionException} is extracted as a + * runtime exception. This is an alternative for client code that does not + * want to deal with checked exceptions. + * + * @param ex the exception to be processed + * @return a {@code ConcurrentRuntimeException} with the checked cause + */ + public static ConcurrentRuntimeException extractCauseUnchecked( + final ExecutionException ex) { + if (ex == null || ex.getCause() == null) { + return null; + } + + throwCause(ex); + return new ConcurrentRuntimeException(ex.getMessage(), ex.getCause()); + } + + /** + * Handles the specified {@code ExecutionException}. This method calls + * {@link #extractCause(ExecutionException)} for obtaining the cause of the + * exception - which might already cause an unchecked exception or an error + * being thrown. If the cause is a checked exception however, it is wrapped + * in a {@code ConcurrentException}, which is thrown. If the passed in + * exception is null or has no cause, the method simply returns + * without throwing an exception. + * + * @param ex the exception to be handled + * @throws ConcurrentException if the cause of the {@code + * ExecutionException} is a checked exception + */ + public static void handleCause(final ExecutionException ex) + throws ConcurrentException { + final ConcurrentException cex = extractCause(ex); + + if (cex != null) { + throw cex; + } + } + + /** + * Handles the specified {@code ExecutionException} and transforms it into a + * runtime exception. This method works exactly like + * {@link #handleCause(ExecutionException)}, but instead of a + * {@link ConcurrentException} it throws a + * {@link ConcurrentRuntimeException}. This is an alternative for client + * code that does not want to deal with checked exceptions. + * + * @param ex the exception to be handled + * @throws ConcurrentRuntimeException if the cause of the {@code + * ExecutionException} is a checked exception; this exception is then + * wrapped in the thrown runtime exception + */ + public static void handleCauseUnchecked(final ExecutionException ex) { + final ConcurrentRuntimeException crex = extractCauseUnchecked(ex); + + if (crex != null) { + throw crex; + } + } + + /** + * Tests whether the specified {@code Throwable} is a checked exception. If + * not, an exception is thrown. + * + * @param ex the {@code Throwable} to check + * @return a flag whether the passed in exception is a checked exception + * @throws IllegalArgumentException if the {@code Throwable} is not a + * checked exception + */ + static Throwable checkedException(final Throwable ex) { + Validate.isTrue(ex != null && !(ex instanceof RuntimeException) + && !(ex instanceof Error), "Not a checked exception: " + ex); + + return ex; + } + + /** + * Tests whether the cause of the specified {@code ExecutionException} + * should be thrown and does it if necessary. + * + * @param ex the exception in question + */ + private static void throwCause(final ExecutionException ex) { + if (ex.getCause() instanceof RuntimeException) { + throw (RuntimeException) ex.getCause(); + } + + if (ex.getCause() instanceof Error) { + throw (Error) ex.getCause(); + } + } + + //----------------------------------------------------------------------- + /** + * Invokes the specified {@code ConcurrentInitializer} and returns the + * object produced by the initializer. This method just invokes the {@code + * get()} method of the given {@code ConcurrentInitializer}. It is + * null-safe: if the argument is null, result is also + * null. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentException if the {@code ConcurrentInitializer} throws + * an exception + */ + public static T initialize(final ConcurrentInitializer initializer) + throws ConcurrentException { + return initializer != null ? initializer.get() : null; + } + + /** + * Invokes the specified {@code ConcurrentInitializer} and transforms + * occurring exceptions to runtime exceptions. This method works like + * {@link #initialize(ConcurrentInitializer)}, but if the {@code + * ConcurrentInitializer} throws a {@link ConcurrentException}, it is + * caught, and the cause is wrapped in a {@link ConcurrentRuntimeException}. + * So client code does not have to deal with checked exceptions. + * + * @param the type of the object produced by the initializer + * @param initializer the {@code ConcurrentInitializer} to be invoked + * @return the object managed by the {@code ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static T initializeUnchecked(final ConcurrentInitializer initializer) { + try { + return initialize(initializer); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Puts a value in the specified {@code ConcurrentMap} if the key is not yet + * present. This method works similar to the {@code putIfAbsent()} method of + * the {@code ConcurrentMap} interface, but the value returned is different. + * Basically, this method is equivalent to the following code fragment: + *

+ * + *
+     * if (!map.containsKey(key)) {
+     *     map.put(key, value);
+     *     return value;
+     * } else {
+     *     return map.get(key);
+     * }
+     * 
+ * + *

+ * except that the action is performed atomically. So this method always + * returns the value which is stored in the map. + *

+ *

+ * This method is null-safe: It accepts a null map as input + * without throwing an exception. In this case the return value is + * null, too. + *

+ * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param value the value to be added + * @return the value stored in the map after this operation + */ + public static V putIfAbsent(final ConcurrentMap map, final K key, final V value) { + if (map == null) { + return null; + } + + final V result = map.putIfAbsent(key, value); + return result != null ? result : value; + } + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not. This method first checks the presence of the key in the + * given map. If it is already contained, its value is returned. Otherwise + * the {@code get()} method of the passed in {@link ConcurrentInitializer} + * is called. With the resulting object + * {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This + * handles the case that in the meantime another thread has added the key to + * the map. Both the map and the initializer can be null; in this + * case this method simply returns null. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentException if the initializer throws an exception + */ +/** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not. This method first checks the presence of the key in the + * given map. If it is already contained, its value is returned. Otherwise + * the {@code get()} method of the passed in {@link ConcurrentInitializer} + * is called. With the resulting object + * {@link #putIfAbsent(ConcurrentMap, Object, Object)} is called. This + * handles the case that in the meantime another thread has added the key to + * the map. Both the map and the initializer can be null; in this + * case this method simply returns null. + * + * @param + * the type of the keys of the map + * @param + * the type of the values of the map + * @param map + * the map to be modified + * @param key + * the key of the value to be added + * @param init + * the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may +not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentException + * if the initializer throws an exception + */ +public static V createIfAbsent(final java.util.concurrent.ConcurrentMap map, final K key, final org.apache.commons.lang3.concurrent.ConcurrentInitializer init) throws org.apache.commons.lang3.concurrent.ConcurrentException { + if ((map == null) || (init == null)) { + return null; + } + final V value = map.get(key); + { + return /* NPEX_NULL_EXP */ + value; + } +} + + /** + * Checks if a concurrent map contains a key and creates a corresponding + * value if not, suppressing checked exceptions. This method calls + * {@code createIfAbsent()}. If a {@link ConcurrentException} is thrown, it + * is caught and re-thrown as a {@link ConcurrentRuntimeException}. + * + * @param the type of the keys of the map + * @param the type of the values of the map + * @param map the map to be modified + * @param key the key of the value to be added + * @param init the {@link ConcurrentInitializer} for creating the value + * @return the value stored in the map after this operation; this may or may + * not be the object created by the {@link ConcurrentInitializer} + * @throws ConcurrentRuntimeException if the initializer throws an exception + */ + public static V createIfAbsentUnchecked(final ConcurrentMap map, + final K key, final ConcurrentInitializer init) { + try { + return createIfAbsent(map, key, init); + } catch (final ConcurrentException cex) { + throw new ConcurrentRuntimeException(cex.getCause()); + } + } + + //----------------------------------------------------------------------- + /** + *

+ * Gets an implementation of Future that is immediately done + * and returns the specified constant value. + *

+ *

+ * This can be useful to return a simple constant immediately from the + * concurrent processing, perhaps as part of avoiding nulls. + * A constant future can also be useful in testing. + *

+ * + * @param the type of the value used by this {@code Future} object + * @param value the constant value to return, may be null + * @return an instance of Future that will return the value, never null + */ + public static Future constantFuture(final T value) { + return new ConstantFuture(value); + } + + /** + * A specialized {@code Future} implementation which wraps a constant value. + * @param the type of the value wrapped by this class + */ + static final class ConstantFuture implements Future { + /** The constant value. */ + private final T value; + + /** + * Creates a new instance of {@code ConstantFuture} and initializes it + * with the constant value. + * + * @param value the value (may be null) + */ + ConstantFuture(final T value) { + this.value = value; + } + + /** + * {@inheritDoc} This implementation always returns true because + * the constant object managed by this {@code Future} implementation is + * always available. + */ + @Override + public boolean isDone() { + return true; + } + + /** + * {@inheritDoc} This implementation just returns the constant value. + */ + @Override + public T get() { + return value; + } + + /** + * {@inheritDoc} This implementation just returns the constant value; it + * does not block, therefore the timeout has no meaning. + */ + @Override + public T get(final long timeout, final TimeUnit unit) { + return value; + } + + /** + * {@inheritDoc} This implementation always returns false; there + * is no background process which could be cancelled. + */ + @Override + public boolean isCancelled() { + return false; + } + + /** + * {@inheritDoc} The cancel operation is not supported. This + * implementation always returns false. + */ + @Override + public boolean cancel(final boolean mayInterruptIfRunning) { + return false; + } + } + +} diff --git a/Java/commons-lang-ConcurrentUtils_278/metadata.json b/Java/commons-lang-ConcurrentUtils_278/metadata.json new file mode 100644 index 000000000..6d5620770 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_278/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-ConcurrentUtils_278", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 304, + "npe_method": "createIfAbsent", + "deref_field": "value", + "npe_class": "ConcurrentUtils", + "repo": "commons-lang", + "bug_id": "ConcurrentUtils_278" + } +} diff --git a/Java/commons-lang-ConcurrentUtils_278/npe.json b/Java/commons-lang-ConcurrentUtils_278/npe.json new file mode 100644 index 000000000..2b0cb3c39 --- /dev/null +++ b/Java/commons-lang-ConcurrentUtils_278/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConcurrentUtils.java", + "line": 304, + "npe_method": "createIfAbsent", + "deref_field": "value", + "npe_class": "ConcurrentUtils" +} \ No newline at end of file diff --git a/Java/commons-lang-ConstantInitializer_91/Dockerfile b/Java/commons-lang-ConstantInitializer_91/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-ConstantInitializer_91/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-ConstantInitializer_91/buggy.java b/Java/commons-lang-ConstantInitializer_91/buggy.java new file mode 100644 index 000000000..9255c0c7b --- /dev/null +++ b/Java/commons-lang-ConstantInitializer_91/buggy.java @@ -0,0 +1,136 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.concurrent; + +import org.apache.commons.lang3.ObjectUtils; + +/** + *

+ * A very simple implementation of the {@link ConcurrentInitializer} interface + * which always returns the same object. + *

+ *

+ * An instance of this class is passed a reference to an object when it is + * constructed. The {@link #get()} method just returns this object. No + * synchronization is required. + *

+ *

+ * This class is useful for instance for unit testing or in cases where a + * specific object has to be passed to an object which expects a + * {@link ConcurrentInitializer}. + *

+ * + * @since 3.0 + * @param the type of the object managed by this initializer + */ +public class ConstantInitializer implements ConcurrentInitializer { + /** Constant for the format of the string representation. */ + private static final String FMT_TO_STRING = "ConstantInitializer@%d [ object = %s ]"; + + /** Stores the managed object. */ + private final T object; + + /** + * Creates a new instance of {@code ConstantInitializer} and initializes it + * with the object to be managed. The {@code get()} method will always + * return the object passed here. This class does not place any restrictions + * on the object. It may be null, then {@code get()} will return + * null, too. + * + * @param obj the object to be managed by this initializer + */ + public ConstantInitializer(final T obj) { + object = obj; + } + + /** + * Directly returns the object that was passed to the constructor. This is + * the same object as returned by {@code get()}. However, this method does + * not declare that it throws an exception. + * + * @return the object managed by this initializer + */ + public final T getObject() { + return object; + } + + /** + * Returns the object managed by this initializer. This implementation just + * returns the object passed to the constructor. + * + * @return the object managed by this initializer + * @throws ConcurrentException if an error occurs + */ + @Override + public T get() throws ConcurrentException { + return getObject(); + } + + /** + * Returns a hash code for this object. This implementation returns the hash + * code of the managed object. + * + * @return a hash code for this object + */ + @Override +/** + * Returns a hash code for this object. This implementation returns the hash + * code of the managed object. + * + * @return a hash code for this object + */ +public int hashCode() { + return /* NPEX_NULL_EXP */ + getObject().hashCode(); +} + + /** + * Compares this object with another one. This implementation returns + * true if and only if the passed in object is an instance of + * {@code ConstantInitializer} which refers to an object equals to the + * object managed by this instance. + * + * @param obj the object to compare to + * @return a flag whether the objects are equal + */ + @SuppressWarnings( "deprecation" ) // ObjectUtils.equals(Object, Object) has been deprecated in 3.2 + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (!(obj instanceof ConstantInitializer)) { + return false; + } + + final ConstantInitializer c = (ConstantInitializer) obj; + return ObjectUtils.equals(getObject(), c.getObject()); + } + + /** + * Returns a string representation for this object. This string also + * contains a string representation of the object managed by this + * initializer. + * + * @return a string for this object + */ + @Override + public String toString() { + return String.format(FMT_TO_STRING, Integer.valueOf(System.identityHashCode(this)), + String.valueOf(getObject())); + } +} diff --git a/Java/commons-lang-ConstantInitializer_91/metadata.json b/Java/commons-lang-ConstantInitializer_91/metadata.json new file mode 100644 index 000000000..72b01cff2 --- /dev/null +++ b/Java/commons-lang-ConstantInitializer_91/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-ConstantInitializer_91", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConstantInitializer.java", + "line": 98, + "npe_method": "hashCode", + "deref_field": "getObject", + "npe_class": "ConstantInitializer", + "repo": "commons-lang", + "bug_id": "ConstantInitializer_91" + } +} diff --git a/Java/commons-lang-ConstantInitializer_91/npe.json b/Java/commons-lang-ConstantInitializer_91/npe.json new file mode 100644 index 000000000..20f32438a --- /dev/null +++ b/Java/commons-lang-ConstantInitializer_91/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/concurrent/ConstantInitializer.java", + "line": 98, + "npe_method": "hashCode", + "deref_field": "getObject", + "npe_class": "ConstantInitializer" +} \ No newline at end of file diff --git a/Java/commons-lang-ConstructorUtils_177/Dockerfile b/Java/commons-lang-ConstructorUtils_177/Dockerfile new file mode 100644 index 000000000..7b7fbe349 --- /dev/null +++ b/Java/commons-lang-ConstructorUtils_177/Dockerfile @@ -0,0 +1,18 @@ +FROM ghcr.io/kupl/starlab-benchmarks/java-base:commons-lang + +ENV TZ=Asia/Seoul + +COPY ./metadata.json . +COPY ./npe.json . +COPY ./buggy.java /tmp/buggy.java +RUN export BUGGY_PATH=$(cat metadata.json | jq -r ".npe.filepath") \ + && export BUGGY_LINE=$(cat metadata.json | jq -r ".npe.line") \ + && export BUGGY_MTHD=$(cat metadata.json | jq -r ".npe.npe_method") \ + && mv /tmp/buggy.java $BUGGY_PATH \ + && echo "[{\"filepath\": \"$BUGGY_PATH\", \"line\": $BUGGY_LINE, \"method_name\": \"$BUGGY_MTHD\"}]" | jq . > traces.json + +RUN git init . && git add -A + +RUN $(cat metadata.json | jq -r ".buildCommand") + +RUN $(cat metadata.json | jq -r ".testCommand"); if [ $? -eq 0 ]; then exit 1; fi diff --git a/Java/commons-lang-ConstructorUtils_177/buggy.java b/Java/commons-lang-ConstructorUtils_177/buggy.java new file mode 100644 index 000000000..2da95ce13 --- /dev/null +++ b/Java/commons-lang-ConstructorUtils_177/buggy.java @@ -0,0 +1,326 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.apache.commons.lang3.reflect; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Modifier; + +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.ClassUtils; +import org.apache.commons.lang3.Validate; + +/** + *

Utility reflection methods focused on constructors, modeled after + * {@link MethodUtils}.

+ * + *

Known Limitations

Accessing Public Constructors In A Default + * Access Superclass

There is an issue when invoking {@code public} constructors + * contained in a default access superclass. Reflection correctly locates these + * constructors and assigns them as {@code public}. However, an + * {@link IllegalAccessException} is thrown if the constructor is + * invoked.

+ * + *

{@link ConstructorUtils} contains a workaround for this situation: it + * will attempt to call {@link java.lang.reflect.AccessibleObject#setAccessible(boolean)} on this constructor. If this + * call succeeds, then the method can be invoked as normal. This call will only + * succeed when the application has sufficient security privileges. If this call + * fails then a warning will be logged and the method may fail.

+ * + * @since 2.5 + */ +public class ConstructorUtils { + + /** + *

ConstructorUtils instances should NOT be constructed in standard + * programming. Instead, the class should be used as + * {@code ConstructorUtils.invokeConstructor(cls, args)}.

+ * + *

This constructor is {@code public} to permit tools that require a JavaBean + * instance to operate.

+ */ + public ConstructorUtils() { + super(); + } + + /** + *

Returns a new instance of the specified class inferring the right constructor + * from the types of the arguments.

+ * + *

This locates and calls a constructor. + * The constructor signature must match the argument types by assignment compatibility.

+ * + * @param the type to be constructed + * @param cls the class to be constructed, not {@code null} + * @param args the array of arguments, {@code null} treated as empty + * @return new instance of {@code cls}, not {@code null} + * + * @throws NullPointerException if {@code cls} is {@code null} + * @throws NoSuchMethodException if a matching constructor cannot be found + * @throws IllegalAccessException if invocation is not permitted by security + * @throws InvocationTargetException if an error occurs on invocation + * @throws InstantiationException if an error occurs on instantiation + * @see #invokeConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[]) + */ + public static T invokeConstructor(final Class cls, Object... args) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, + InstantiationException { + args = ArrayUtils.nullToEmpty(args); + final Class parameterTypes[] = ClassUtils.toClass(args); + return invokeConstructor(cls, args, parameterTypes); + } + + /** + *

Returns a new instance of the specified class choosing the right constructor + * from the list of parameter types.

+ * + *

This locates and calls a constructor. + * The constructor signature must match the parameter types by assignment compatibility.

+ * + * @param the type to be constructed + * @param cls the class to be constructed, not {@code null} + * @param args the array of arguments, {@code null} treated as empty + * @param parameterTypes the array of parameter types, {@code null} treated as empty + * @return new instance of {@code cls}, not {@code null} + * + * @throws NullPointerException if {@code cls} is {@code null} + * @throws NoSuchMethodException if a matching constructor cannot be found + * @throws IllegalAccessException if invocation is not permitted by security + * @throws InvocationTargetException if an error occurs on invocation + * @throws InstantiationException if an error occurs on instantiation + * @see Constructor#newInstance + */ + public static T invokeConstructor(final Class cls, Object[] args, Class[] parameterTypes) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, + InstantiationException { + args = ArrayUtils.nullToEmpty(args); + parameterTypes = ArrayUtils.nullToEmpty(parameterTypes); + final Constructor ctor = getMatchingAccessibleConstructor(cls, parameterTypes); + if (ctor == null) { + throw new NoSuchMethodException( + "No such accessible constructor on object: " + cls.getName()); + } + if (ctor.isVarArgs()) { + Class[] methodParameterTypes = ctor.getParameterTypes(); + args = MethodUtils.getVarArgs(args, methodParameterTypes); + } + return ctor.newInstance(args); + } + + /** + *

Returns a new instance of the specified class inferring the right constructor + * from the types of the arguments.

+ * + *

This locates and calls a constructor. + * The constructor signature must match the argument types exactly.

+ * + * @param the type to be constructed + * @param cls the class to be constructed, not {@code null} + * @param args the array of arguments, {@code null} treated as empty + * @return new instance of {@code cls}, not {@code null} + * + * @throws NullPointerException if {@code cls} is {@code null} + * @throws NoSuchMethodException if a matching constructor cannot be found + * @throws IllegalAccessException if invocation is not permitted by security + * @throws InvocationTargetException if an error occurs on invocation + * @throws InstantiationException if an error occurs on instantiation + * @see #invokeExactConstructor(java.lang.Class, java.lang.Object[], java.lang.Class[]) + */ + public static T invokeExactConstructor(final Class cls, Object... args) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, + InstantiationException { + args = ArrayUtils.nullToEmpty(args); + final Class parameterTypes[] = ClassUtils.toClass(args); + return invokeExactConstructor(cls, args, parameterTypes); + } + + /** + *

Returns a new instance of the specified class choosing the right constructor + * from the list of parameter types.

+ * + *

This locates and calls a constructor. + * The constructor signature must match the parameter types exactly.

+ * + * @param the type to be constructed + * @param cls the class to be constructed, not {@code null} + * @param args the array of arguments, {@code null} treated as empty + * @param parameterTypes the array of parameter types, {@code null} treated as empty + * @return new instance of cls, not {@code null} + * + * @throws NullPointerException if {@code cls} is {@code null} + * @throws NoSuchMethodException if a matching constructor cannot be found + * @throws IllegalAccessException if invocation is not permitted by security + * @throws InvocationTargetException if an error occurs on invocation + * @throws InstantiationException if an error occurs on instantiation + * @see Constructor#newInstance + */ +/** + *

Returns a new instance of the specified class choosing the right constructor + * from the list of parameter types.

+ * + *

This locates and calls a constructor. + * The constructor signature must match the parameter types exactly.

+ * + * @param + * the type to be constructed + * @param cls + * the class to be constructed, not {@code null} + * @param args + * the array of arguments, {@code null} treated as empty + * @param parameterTypes + * the array of parameter types, {@code null} treated as empty + * @return new instance of cls, not {@code null} + * @throws NullPointerException + * if {@code cls} is {@code null} + * @throws NoSuchMethodException + * if a matching constructor cannot be found + * @throws IllegalAccessException + * if invocation is not permitted by security + * @throws InvocationTargetException + * if an error occurs on invocation + * @throws InstantiationException + * if an error occurs on instantiation + * @see Constructor#newInstance + */ +public static T invokeExactConstructor(final java.lang.Class cls, java.lang.Object[] args, java.lang.Class[] parameterTypes) throws java.lang.NoSuchMethodException, java.lang.IllegalAccessException, java.lang.reflect.InvocationTargetException, java.lang.InstantiationException { + args = org.apache.commons.lang3.ArrayUtils.nullToEmpty(args); + parameterTypes = org.apache.commons.lang3.ArrayUtils.nullToEmpty(parameterTypes); + final java.lang.reflect.Constructor ctor = org.apache.commons.lang3.reflect.ConstructorUtils.getAccessibleConstructor(cls, parameterTypes); + { + return /* NPEX_NULL_EXP */ + ctor.newInstance(args); + } +} + + //----------------------------------------------------------------------- + /** + *

Finds a constructor given a class and signature, checking accessibility.

+ * + *

This finds the constructor and ensures that it is accessible. + * The constructor signature must match the parameter types exactly.

+ * + * @param the constructor type + * @param cls the class to find a constructor for, not {@code null} + * @param parameterTypes the array of parameter types, {@code null} treated as empty + * @return the constructor, {@code null} if no matching accessible constructor found + * @see Class#getConstructor + * @see #getAccessibleConstructor(java.lang.reflect.Constructor) + * @throws NullPointerException if {@code cls} is {@code null} + */ + public static Constructor getAccessibleConstructor(final Class cls, + final Class... parameterTypes) { + Validate.notNull(cls, "class cannot be null"); + try { + return getAccessibleConstructor(cls.getConstructor(parameterTypes)); + } catch (final NoSuchMethodException e) { + return null; + } + } + + /** + *

Checks if the specified constructor is accessible.

+ * + *

This simply ensures that the constructor is accessible.

+ * + * @param the constructor type + * @param ctor the prototype constructor object, not {@code null} + * @return the constructor, {@code null} if no matching accessible constructor found + * @see java.lang.SecurityManager + * @throws NullPointerException if {@code ctor} is {@code null} + */ + public static Constructor getAccessibleConstructor(final Constructor ctor) { + Validate.notNull(ctor, "constructor cannot be null"); + return MemberUtils.isAccessible(ctor) + && isAccessible(ctor.getDeclaringClass()) ? ctor : null; + } + + /** + *

Finds an accessible constructor with compatible parameters.

+ * + *

This checks all the constructor and finds one with compatible parameters + * This requires that every parameter is assignable from the given parameter types. + * This is a more flexible search than the normal exact matching algorithm.

+ * + *

First it checks if there is a constructor matching the exact signature. + * If not then all the constructors of the class are checked to see if their + * signatures are assignment-compatible with the parameter types. + * The first assignment-compatible matching constructor is returned.

+ * + * @param the constructor type + * @param cls the class to find a constructor for, not {@code null} + * @param parameterTypes find method with compatible parameters + * @return the constructor, null if no matching accessible constructor found + * @throws NullPointerException if {@code cls} is {@code null} + */ + public static Constructor getMatchingAccessibleConstructor(final Class cls, + final Class... parameterTypes) { + Validate.notNull(cls, "class cannot be null"); + // see if we can find the constructor directly + // most of the time this works and it's much faster + try { + final Constructor ctor = cls.getConstructor(parameterTypes); + MemberUtils.setAccessibleWorkaround(ctor); + return ctor; + } catch (final NoSuchMethodException e) { // NOPMD - Swallow + } + Constructor result = null; + /* + * (1) Class.getConstructors() is documented to return Constructor so as + * long as the array is not subsequently modified, everything's fine. + */ + final Constructor[] ctors = cls.getConstructors(); + + // return best match: + for (Constructor ctor : ctors) { + // compare parameters + if (MemberUtils.isMatchingConstructor(ctor, parameterTypes)) { + // get accessible version of constructor + ctor = getAccessibleConstructor(ctor); + if (ctor != null) { + MemberUtils.setAccessibleWorkaround(ctor); + if (result == null || MemberUtils.compareConstructorFit(ctor, result, parameterTypes) < 0) { + // temporary variable for annotation, see comment above (1) + @SuppressWarnings("unchecked") + final + Constructor constructor = (Constructor)ctor; + result = constructor; + } + } + } + } + return result; + } + + /** + * Learn whether the specified class is generally accessible, i.e. is + * declared in an entirely {@code public} manner. + * @param type to check + * @return {@code true} if {@code type} and any enclosing classes are + * {@code public}. + */ + private static boolean isAccessible(final Class type) { + Class cls = type; + while (cls != null) { + if (!Modifier.isPublic(cls.getModifiers())) { + return false; + } + cls = cls.getEnclosingClass(); + } + return true; + } + +} diff --git a/Java/commons-lang-ConstructorUtils_177/metadata.json b/Java/commons-lang-ConstructorUtils_177/metadata.json new file mode 100644 index 000000000..1f3bf3534 --- /dev/null +++ b/Java/commons-lang-ConstructorUtils_177/metadata.json @@ -0,0 +1,21 @@ +{ + "language": "java", + "id": "commons-lang-ConstructorUtils_177", + "buggyPath": ".", + "referencePath": null, + "buildCommand": "mvn package -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100 -DskipTests=true -DskipITs=true -Dtest=None -DfailIfNoTests=false", + "testCommand": "mvn test -V -B -Denforcer.skip=true -Dcheckstyle.skip=true -Dcobertura.skip=true -Drat.skip=true -Dlicense.skip=true -Dfindbugs.skip=true -Dgpg.skip=true -Dskip.npm=true -Dskip.gulp=true -Dskip.bower=true -Drat.numUnapprovedLicenses=100", + "categories": [ + "safety", + "npe" + ], + "npe": { + "filepath": "src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java", + "line": 205, + "npe_method": "invokeExactConstructor", + "deref_field": "ctor", + "npe_class": "ConstructorUtils", + "repo": "commons-lang", + "bug_id": "ConstructorUtils_177" + } +} diff --git a/Java/commons-lang-ConstructorUtils_177/npe.json b/Java/commons-lang-ConstructorUtils_177/npe.json new file mode 100644 index 000000000..d0229a661 --- /dev/null +++ b/Java/commons-lang-ConstructorUtils_177/npe.json @@ -0,0 +1,7 @@ +{ + "filepath": "src/main/java/org/apache/commons/lang3/reflect/ConstructorUtils.java", + "line": 205, + "npe_method": "invokeExactConstructor", + "deref_field": "ctor", + "npe_class": "ConstructorUtils" +} \ No newline at end of file