- Mutation Operators
- Status Code Mutation Operators
- Header Mutation Operators
- JSON Mutation Operators
- AEA - Array Element Addition
- AER - Array Element Removal
- AEE - Array Elements Exchange
- EAS - Empty Array Setting
- OPA - Object Property Addition
- OPR - Object Property Removal
- OTPR - Object-Type Property Removal
- PTC - Property Type Change
- BPR - Boolean Property Reverse
- NPS - Null Property Setting
- NPR - Numeric Property Replacement
- SPR - String Property Replacement
- SCA - Special Characters Addition
- SRE - String Length Reduction/Extension
- Extending Mutation Operators
This document explains how each mutation operator is applied, what it can act on, and what the resulting mutant looks like.
- Mutator: classes that extend
AbstractMutatorand choose which operator to apply for a given JSON node or header component. Examples:StatusCodeMutator,HeaderMutator,BodyMutator, plus type-specific mutators underhttpmutator-core/src/main/java/es/us/isa/httpmutator/core/.... - Operator: classes that extend
AbstractOperatorand implementdoMutate(...). These live under.../operator/packages. - Flow: a mutator scans one recorded HTTP response (status, headers, JSON body) and picks the applicable operator(s) for each target part; each operator performs one small change to produce a mutant variant, which is then collected and exported as JSONL (optionally .jsonl.zst shards), HAR, or kept in memory.
Replaces the status code with a 2XX success code to simulate incorrectly successful responses (code uses {200, 201, 202, 204} and does not include 202).
- Input must be an integer HTTP status code.
import es.us.isa.httpmutator.core.sc.operator.StatusCodeReplacementWith20XOperator;
public class Example {
public static void main(String[] args) throws Exception {
StatusCodeReplacementWith20XOperator op = new StatusCodeReplacementWith20XOperator();
int mutated = (int) op.mutate(400);
}
}Result: returns a different 2xx status code (int) chosen from {200, 201, 204}. Example: 400 -> 200.
Replaces the status code with a 4XX client-error code to simulate incorrect error responses.
- Input must be an integer HTTP status code.
import es.us.isa.httpmutator.core.sc.operator.StatusCodeReplacementWith40XOperator;
public class Example {
public static void main(String[] args) throws Exception {
StatusCodeReplacementWith40XOperator op = new StatusCodeReplacementWith40XOperator();
int mutated = (int) op.mutate(200);
}
}Result: returns a different 4xx status code (int) chosen from {400, 401, 403, 404, 409}. Example: 200 -> 400.
Replaces the status code with a 5XX server-error code to simulate unexpected failures (code includes 501).
- Input must be an integer HTTP status code.
import es.us.isa.httpmutator.core.sc.operator.StatusCodeReplacementWith50XOperator;
public class Example {
public static void main(String[] args) throws Exception {
StatusCodeReplacementWith50XOperator op = new StatusCodeReplacementWith50XOperator();
int mutated = (int) op.mutate(200);
}
}Result: returns a different 5xx status code (int) chosen from {500, 501, 502, 503, 504}. Example: 200 -> 503.
Replaces the media type portion of Content-Type with another common media type.
- Input must be a media type string from the Content-Type header (e.g., application/json).
import es.us.isa.httpmutator.core.headers.mediaType.operator.MediaTypeReplacementOperator;
public class Example {
public static void main(String[] args) throws Exception {
MediaTypeReplacementOperator op = new MediaTypeReplacementOperator();
String mutated = (String) op.mutate("application/json");
}
}Result: returns a different media type string (e.g., text/plain) for the Content-Type header. Example: "application/json" -> "text/plain".
Deletes the media type portion of Content-Type, leaving only parameters like charset.
- Input must be a media type string from the Content-Type header.
import es.us.isa.httpmutator.core.body.value.common.operator.NullOperator;
import es.us.isa.httpmutator.core.headers.mediaType.MediaTypeMutator;
public class Example {
public static void main(String[] args) throws Exception {
NullOperator op = new NullOperator(MediaTypeMutator.class);
Object mutated = op.mutate("application/json");
}
}Result: returns null to indicate the media type should be removed. Example: "application/json" -> null.
Replaces the charset parameter in Content-Type; if charset is missing, code may insert one.
- Input must be a charset string (e.g., utf-8) or null when missing.
import es.us.isa.httpmutator.core.headers.charset.operator.CharsetReplacementOperator;
public class Example {
public static void main(String[] args) throws Exception {
CharsetReplacementOperator op = new CharsetReplacementOperator();
String mutated = (String) op.mutate("utf-8");
}
}Result: returns a different charset string (or inserts one if input is null). Example: "utf-8" -> "UTF-16".
Deletes the charset parameter in Content-Type.
- Input must be a charset string from the Content-Type header.
import es.us.isa.httpmutator.core.body.value.common.operator.NullOperator;
import es.us.isa.httpmutator.core.headers.charset.CharsetMutator;
public class Example {
public static void main(String[] args) throws Exception {
NullOperator op = new NullOperator(CharsetMutator.class);
Object mutated = op.mutate("utf-8");
}
}Result: returns null to indicate the charset should be removed. Example: "utf-8" -> null.
Modifies the Location header by appending /<currentTimeMillis> to the URI path.
- Input must be a Location header value string parseable as a URI.
import es.us.isa.httpmutator.core.headers.location.operator.LocationMutationOperator;
public class Example {
public static void main(String[] args) throws Exception {
LocationMutationOperator op = new LocationMutationOperator();
String mutated = (String) op.mutate("https://example.org/items/1");
}
}Result: returns a new Location URI string with a modified path. Example: "https://example.org/items/1" -> "https://example.org/items/1/123456789".
Deletes the Location header.
- Input must be a Location header value string.
import es.us.isa.httpmutator.core.body.value.common.operator.NullOperator;
import es.us.isa.httpmutator.core.headers.location.LocationMutator;
public class Example {
public static void main(String[] args) throws Exception {
NullOperator op = new NullOperator(LocationMutator.class);
Object mutated = op.mutate("https://example.org/items/1");
}
}Result: returns null to indicate the Location header should be removed. Example: "https://example.org/items/1" -> null.
Inserts new elements into an existing array.
- Input must be a JSON array node (ArrayNode).
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import es.us.isa.httpmutator.core.body.array.operator.ArrayAddElementOperator;
public class Example {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ArrayNode items = (ArrayNode) mapper.readTree("[1]");
ArrayAddElementOperator op = new ArrayAddElementOperator();
ArrayNode mutated = (ArrayNode) op.mutate(items);
}
}Result: returns the ArrayNode with one or more new elements appended. Example: [1] -> [1, 0].
Removes elements from an array; isApplicable(...) requires the array size to exceed operator.array.removedElements.max.
- Input must be a JSON array node (ArrayNode).
- Array size must be greater than the configured max removed count.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import es.us.isa.httpmutator.core.body.array.operator.ArrayRemoveElementOperator;
public class Example {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ArrayNode items = (ArrayNode) mapper.readTree("[1,2,3,4,5]");
ArrayRemoveElementOperator op = new ArrayRemoveElementOperator();
ArrayNode mutated = (ArrayNode) op.mutate(items);
}
}Result: returns the ArrayNode with one or more elements removed. Example: [1,2,3,4,5] -> [1,2,4,5].
Reorders an array by moving one element to a different position.
- Input must be a JSON array node (ArrayNode) with size > 1.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import es.us.isa.httpmutator.core.body.array.operator.ArrayDisorderElementsOperator;
public class Example {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ArrayNode items = (ArrayNode) mapper.readTree("[\"a\",\"b\"]");
ArrayDisorderElementsOperator op = new ArrayDisorderElementsOperator();
ArrayNode mutated = (ArrayNode) op.mutate(items);
}
}Result: returns the ArrayNode with elements reordered. Example: ["a","b"] -> ["b","a"].
Clears all elements from a non-empty array.
- Input must be a JSON array node (ArrayNode) with size > 0.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ArrayNode;
import es.us.isa.httpmutator.core.body.array.operator.ArrayEmptyOperator;
public class Example {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ArrayNode items = (ArrayNode) mapper.readTree("[1]");
ArrayEmptyOperator op = new ArrayEmptyOperator();
ArrayNode mutated = (ArrayNode) op.mutate(items);
}
}Result: returns the ArrayNode with all elements removed (empty array). Example: [1] -> [].
Adds new properties to a JSON object.
- Input must be a JSON object node (ObjectNode).
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import es.us.isa.httpmutator.core.body.object.operator.ObjectAddElementOperator;
public class Example {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ObjectNode obj = (ObjectNode) mapper.readTree("{\"id\":1}");
ObjectAddElementOperator op = new ObjectAddElementOperator();
ObjectNode mutated = (ObjectNode) op.mutate(obj);
}
}Result: returns the ObjectNode with one or more new properties added. Example: {"id":1} -> {"id":1,"randomLong1":42}.
Removes existing properties from a JSON object.
- Input must be a JSON object node (ObjectNode) with at least one property.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import es.us.isa.httpmutator.core.body.object.operator.ObjectRemoveElementOperator;
public class Example {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ObjectNode obj = (ObjectNode) mapper.readTree("{\"id\":1,\"name\":\"x\"}");
ObjectRemoveElementOperator op = new ObjectRemoveElementOperator();
ObjectNode mutated = (ObjectNode) op.mutate(obj);
}
}Result: returns the ObjectNode with one or more properties removed. Example: {"id":1,"name":"x"} -> {"id":1}.
Removes object-valued properties from a JSON object; current code only keeps the last discovered object-type property as a removal candidate.
- Input must be a JSON object node (ObjectNode) that contains at least one object-valued property.
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
import es.us.isa.httpmutator.core.body.object.operator.ObjectRemoveObjectTypeElementOperator;
public class Example {
public static void main(String[] args) throws Exception {
ObjectMapper mapper = new ObjectMapper();
ObjectNode obj = (ObjectNode) mapper.readTree("{\"a\":1,\"details\":{\"x\":2}}");
ObjectRemoveObjectTypeElementOperator op = new ObjectRemoveObjectTypeElementOperator();
ObjectNode mutated = (ObjectNode) op.mutate(obj);
}
}Result: returns the ObjectNode with an object-valued property removed. Example: {"a":1,"details":{"x":2}} -> {"a":1}.
Changes the type of a JSON node to a different type; for root-level object/array bodies, BodyMutator.resetFirstLevelOperators() removes this operator so it applies to nested nodes.
- Input must be a JSON value (array, object, string, number, boolean, or null).
import es.us.isa.httpmutator.core.body.value.common.operator.ChangeTypeOperator;
public class Example {
public static void main(String[] args) throws Exception {
ChangeTypeOperator op = new ChangeTypeOperator(String.class);
Object mutated = op.mutate("abc");
}
}Result: returns a value of a different JSON type than the input. Example: "abc" -> 42.
Flips a boolean value.
- Input must be a boolean value.
import es.us.isa.httpmutator.core.body.value.boolean0.operator.BooleanMutationOperator;
public class Example {
public static void main(String[] args) throws Exception {
BooleanMutationOperator op = new BooleanMutationOperator();
boolean mutated = (boolean) op.mutate(true);
}
}Result: returns the negated boolean value. Example: true -> false.
Replaces a value with JSON null; for root-level object/array bodies, BodyMutator.resetFirstLevelOperators() removes this operator so it applies to nested nodes.
- Input must be a JSON value (array, object, string, number, or boolean).
import es.us.isa.httpmutator.core.body.value.common.operator.NullOperator;
public class Example {
public static void main(String[] args) throws Exception {
NullOperator op = new NullOperator(String.class);
Object mutated = op.mutate("abc");
}
}Result: returns null. Example: "abc" -> null.
Replaces a numeric value with another numeric value in the configured range.
- Input must be an integral or floating-point number.
import es.us.isa.httpmutator.core.body.value.long0.operator.LongReplacementOperator;
import es.us.isa.httpmutator.core.body.value.double0.operator.DoubleReplacementOperator;
public class Example {
public static void main(String[] args) throws Exception {
LongReplacementOperator longOp = new LongReplacementOperator();
DoubleReplacementOperator doubleOp = new DoubleReplacementOperator();
long mutatedLong = (long) longOp.mutate(10L);
double mutatedDouble = (double) doubleOp.mutate(1.5d);
}
}Result: returns a numeric value within the configured range. Example: 10 -> 42.
Replaces a string value with a randomly generated string.
- Input must be a string value.
import es.us.isa.httpmutator.core.body.value.string0.operator.StringReplacementOperator;
public class Example {
public static void main(String[] args) throws Exception {
StringReplacementOperator op = new StringReplacementOperator();
String mutated = (String) op.mutate("abc");
}
}Result: returns a new randomly generated string. Example: "abc" -> "Q9x@L".
Inserts special characters into a string value.
- Input must be a string value (empty strings are allowed).
import es.us.isa.httpmutator.core.body.value.string0.operator.StringAddSpecialCharactersMutationOperator;
public class Example {
public static void main(String[] args) throws Exception {
StringAddSpecialCharactersMutationOperator op = new StringAddSpecialCharactersMutationOperator();
String mutated = (String) op.mutate("abc");
}
}Result: returns the string with special characters inserted. Example: "abc" -> "a/bc".
Replaces a string value with boundary cases (empty, min/max length, lowercase/uppercase).
- Input must be a string value.
import es.us.isa.httpmutator.core.body.value.string0.operator.StringBoundaryOperator;
public class Example {
public static void main(String[] args) throws Exception {
StringBoundaryOperator op = new StringBoundaryOperator();
String mutated = (String) op.mutate("abc");
}
}Result: returns a boundary-case string (empty, min/max length, lowercase, or uppercase). Example: "abc" -> "".
HttpMutator is extensible by design and mutation behavior is extended by adding new mutation operators. Operators are applied by mutators during traversal of responses and produce concrete mutant values. This section describes the supported extension path for operators.
A mutation operator represents one concrete change to a value.
Operators extend AbstractOperator and define two required behaviors in this codebase:
protected Object doMutate(Object element)implements the actual mutation and returns the mutated value.public boolean isApplicable(Object element)restricts where the operator can be applied so that incompatible inputs are skipped.
The ExampleOperator below illustrates this contract for string values.
isApplicable(...) returns true only when the input is a String, so the operator is applied only to string-typed locations discovered by the mutator.
doMutate(...) implements the mutation by appending the suffix "_mut" to the original value.
A string value such as "book" is therefore mutated into "book_mut", while non-string values are ignored by this operator.
import es.us.isa.httpmutator.core.AbstractOperator;
public class ExampleOperator extends AbstractOperator {
@Override
protected Object doMutate(Object value) {
return String.valueOf(value) + "_mut";
}
@Override
public boolean isApplicable(Object value) {
return value instanceof String;
}
}Mutators select mutation targets and apply mutation operators using an operator map.
An operator becomes available to a mutator after it is inserted into that map via getOperators().put(...).
Registration is typically performed by extending an existing mutator such as StringMutator.
Minimal mutator integration example:
import es.us.isa.httpmutator.core.body.value.string0.StringMutator;
import es.us.isa.httpmutator.core.util.OperatorNames;
public class CustomStringMutator extends StringMutator {
public CustomStringMutator() {
super();
getOperators().put(OperatorNames.REPLACE, new ExampleOperator());
}
}