JsonText.java

1
package org.egothor.methodatlas.ai;
2
3
/**
4
 * Utility methods for extracting JSON fragments from free-form text produced by
5
 * AI model responses.
6
 *
7
 * <p>
8
 * Some AI providers may return textual responses that contain additional
9
 * commentary or formatting around the actual JSON payload requested by the
10
 * application. This helper provides a minimal extraction mechanism that
11
 * isolates the first JSON object found within such responses so that it can be
12
 * deserialized safely.
13
 * </p>
14
 *
15
 * <p>
16
 * The current implementation performs a simple structural search for the first
17
 * opening brace (<code>{</code>) and the last closing brace (<code>}</code>),
18
 * and returns the substring spanning those positions.
19
 * </p>
20
 *
21
 * <p>
22
 * The method is intentionally tolerant of provider-specific output formats and
23
 * is primarily used as a defensive measure to recover valid JSON payloads from
24
 * otherwise well-formed responses.
25
 * </p>
26
 *
27
 * <p>
28
 * This class is a non-instantiable utility holder.
29
 * </p>
30
 *
31
 * @see AiSuggestionException
32
 * @see AiClassSuggestion
33
 */
34
public final class JsonText {
35
    /**
36
     * Prevents instantiation of this utility class.
37
     */
38
    private JsonText() {
39
    }
40
41
    /**
42
     * Extracts the first JSON object found within a text response.
43
     *
44
     * <p>
45
     * The method scans the supplied text for the first occurrence of an opening
46
     * brace (<code>{</code>) and the last occurrence of a closing brace
47
     * (<code>}</code>). The substring between these positions (inclusive) is
48
     * returned as the extracted JSON object.
49
     * </p>
50
     *
51
     * <p>
52
     * This approach allows the application to recover structured data even when the
53
     * model returns additional natural-language content or formatting around the
54
     * JSON payload.
55
     * </p>
56
     *
57
     * @param text text returned by the AI model
58
     * @return extracted JSON object as text
59
     *
60
     * @throws AiSuggestionException if the input text is empty or if no valid JSON
61
     *                               object boundaries can be located
62
     */
63
    public static String extractFirstJsonObject(String text) throws AiSuggestionException {
64 4 1. extractFirstJsonObject : removed conditional - replaced equality check with false → KILLED
2. extractFirstJsonObject : removed conditional - replaced equality check with true → KILLED
3. extractFirstJsonObject : removed conditional - replaced equality check with false → KILLED
4. extractFirstJsonObject : removed conditional - replaced equality check with true → KILLED
        if (text == null || text.isBlank()) {
65
            throw new AiSuggestionException("Model returned an empty response");
66
        }
67
68
        int start = text.indexOf('{');
69
        int end = text.lastIndexOf('}');
70
71 9 1. extractFirstJsonObject : changed conditional boundary → SURVIVED
2. extractFirstJsonObject : changed conditional boundary → SURVIVED
3. extractFirstJsonObject : removed conditional - replaced comparison check with true → SURVIVED
4. extractFirstJsonObject : removed conditional - replaced comparison check with true → SURVIVED
5. extractFirstJsonObject : removed conditional - replaced comparison check with false → KILLED
6. extractFirstJsonObject : removed conditional - replaced comparison check with false → KILLED
7. extractFirstJsonObject : changed conditional boundary → KILLED
8. extractFirstJsonObject : removed conditional - replaced comparison check with false → KILLED
9. extractFirstJsonObject : removed conditional - replaced comparison check with true → KILLED
        if (start < 0 || end < 0 || end < start) {
72
            throw new AiSuggestionException("Model response does not contain a JSON object: " + text);
73
        }
74
75 2 1. extractFirstJsonObject : replaced return value with "" for org/egothor/methodatlas/ai/JsonText::extractFirstJsonObject → KILLED
2. extractFirstJsonObject : Replaced integer addition with subtraction → KILLED
        return text.substring(start, end + 1);
76
    }
77
}

Mutations

64

1.1
Location : extractFirstJsonObject
Killed by : org.egothor.methodatlas.ai.JsonTextTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.JsonTextTest]/[method:extractFirstJsonObject_returnsJsonWhenInputIsExactlyJson()]
removed conditional - replaced equality check with false → KILLED

2.2
Location : extractFirstJsonObject
Killed by : org.egothor.methodatlas.ai.JsonTextTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.JsonTextTest]/[method:extractFirstJsonObject_returnsJsonWhenInputIsExactlyJson()]
removed conditional - replaced equality check with true → KILLED

3.3
Location : extractFirstJsonObject
Killed by : org.egothor.methodatlas.ai.JsonTextTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.JsonTextTest]/[method:extractFirstJsonObject_blankInput_throwsAiSuggestionException()]
removed conditional - replaced equality check with false → KILLED

4.4
Location : extractFirstJsonObject
Killed by : org.egothor.methodatlas.ai.JsonTextTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.JsonTextTest]/[method:extractFirstJsonObject_nullInput_throwsAiSuggestionException()]
removed conditional - replaced equality check with true → KILLED

71

1.1
Location : extractFirstJsonObject
Killed by : org.egothor.methodatlas.ai.JsonTextTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.JsonTextTest]/[method:extractFirstJsonObject_returnsJsonWhenInputIsExactlyJson()]
removed conditional - replaced comparison check with false → KILLED

2.2
Location : extractFirstJsonObject
Killed by : org.egothor.methodatlas.ai.JsonTextTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.JsonTextTest]/[method:extractFirstJsonObject_returnsJsonWhenInputIsExactlyJson()]
removed conditional - replaced comparison check with false → KILLED

3.3
Location : extractFirstJsonObject
Killed by : none
changed conditional boundary → SURVIVED
Covering tests

4.4
Location : extractFirstJsonObject
Killed by : none
changed conditional boundary → SURVIVED Covering tests

5.5
Location : extractFirstJsonObject
Killed by : org.egothor.methodatlas.ai.JsonTextTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.JsonTextTest]/[method:extractFirstJsonObject_returnsJsonWhenInputIsExactlyJson()]
changed conditional boundary → KILLED

6.6
Location : extractFirstJsonObject
Killed by : none
removed conditional - replaced comparison check with true → SURVIVED Covering tests

7.7
Location : extractFirstJsonObject
Killed by : none
removed conditional - replaced comparison check with true → SURVIVED Covering tests

8.8
Location : extractFirstJsonObject
Killed by : org.egothor.methodatlas.ai.JsonTextTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.JsonTextTest]/[method:extractFirstJsonObject_closingBraceBeforeOpeningBrace_throwsAiSuggestionException()]
removed conditional - replaced comparison check with false → KILLED

9.9
Location : extractFirstJsonObject
Killed by : org.egothor.methodatlas.ai.JsonTextTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.JsonTextTest]/[method:extractFirstJsonObject_returnsJsonWhenInputIsExactlyJson()]
removed conditional - replaced comparison check with true → KILLED

75

1.1
Location : extractFirstJsonObject
Killed by : org.egothor.methodatlas.ai.JsonTextTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.JsonTextTest]/[method:extractFirstJsonObject_returnsJsonWhenInputIsExactlyJson()]
replaced return value with "" for org/egothor/methodatlas/ai/JsonText::extractFirstJsonObject → KILLED

2.2
Location : extractFirstJsonObject
Killed by : org.egothor.methodatlas.ai.JsonTextTest.[engine:junit-jupiter]/[class:org.egothor.methodatlas.ai.JsonTextTest]/[method:extractFirstJsonObject_returnsJsonWhenInputIsExactlyJson()]
Replaced integer addition with subtraction → KILLED

Active mutators

Tests examined


Report generated by PIT 1.22.1