or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

assertions.mdcomparators.mdcomparison.mdcustom-matchers.mdindex.md

custom-matchers.mddocs/

0

# Custom Value Matching

1

2

Advanced validation system enabling custom field-level matching with regular expressions, array validation, and path-based customization for complex JSON structures. This system allows you to define custom comparison logic for specific JSON paths or value types.

3

4

## Capabilities

5

6

### Value Matcher Interface

7

8

Core interface for implementing custom value comparison logic.

9

10

```java { .api }

11

public interface ValueMatcher<T> {

12

/**

13

* Compares two objects for equality using custom logic.

14

*

15

* @param o1 the first object to check

16

* @param o2 the object to check the first against

17

* @return true if the objects are equal, false otherwise

18

*/

19

boolean equal(T o1, T o2);

20

}

21

```

22

23

**Usage Examples:**

24

25

```java

26

// Custom matcher for case-insensitive string comparison

27

ValueMatcher<Object> caseInsensitiveMatcher = new ValueMatcher<Object>() {

28

@Override

29

public boolean equal(Object o1, Object o2) {

30

if (o1 instanceof String && o2 instanceof String) {

31

return ((String) o1).equalsIgnoreCase((String) o2);

32

}

33

return Objects.equals(o1, o2);

34

}

35

};

36

37

// Use with customization

38

Customization customization = new Customization("user.name", caseInsensitiveMatcher);

39

CustomComparator comparator = new CustomComparator(JSONCompareMode.LENIENT, customization);

40

JSONAssert.assertEquals(expected, actual, comparator);

41

```

42

43

### Location-Aware Value Matcher

44

45

Extended interface providing context about the JSON path being compared and access to the comparison result for advanced error handling.

46

47

```java { .api }

48

public interface LocationAwareValueMatcher<T> extends ValueMatcher<T> {

49

/**

50

* Compare values with location context and result access.

51

*

52

* @param prefix JSON path of the JSON item being tested

53

* @param actual JSON value being tested

54

* @param expected expected JSON value

55

* @param result JSONCompareResult to which match failure may be passed

56

* @return true if expected and actual equal or difference already passed to result

57

* @throws ValueMatcherException if custom error message needed

58

*/

59

boolean equal(String prefix, T actual, T expected, JSONCompareResult result) throws ValueMatcherException;

60

}

61

```

62

63

### Regular Expression Matcher

64

65

Matches string values against regular expression patterns with support for both static and dynamic patterns.

66

67

```java { .api }

68

public class RegularExpressionValueMatcher<T> implements ValueMatcher<T> {

69

/**

70

* Create matcher with dynamic pattern from expected value.

71

*/

72

public RegularExpressionValueMatcher();

73

74

/**

75

* Create matcher with constant pattern.

76

*

77

* @param pattern regular expression pattern, null for dynamic mode

78

* @throws IllegalArgumentException if pattern is invalid

79

*/

80

public RegularExpressionValueMatcher(String pattern) throws IllegalArgumentException;

81

82

public boolean equal(T actual, T expected);

83

}

84

```

85

86

**Usage Examples:**

87

88

```java

89

// Static pattern - all values must match this regex

90

RegularExpressionValueMatcher<Object> emailMatcher =

91

new RegularExpressionValueMatcher<>("^[\\w._%+-]+@[\\w.-]+\\.[A-Z]{2,}$");

92

93

// Dynamic pattern - expected value contains the regex

94

RegularExpressionValueMatcher<Object> dynamicMatcher =

95

new RegularExpressionValueMatcher<>();

96

97

// Use with customization for email validation

98

Customization emailCustomization = new Customization("user.email", emailMatcher);

99

CustomComparator comparator = new CustomComparator(JSONCompareMode.LENIENT, emailCustomization);

100

101

// Test with dynamic pattern

102

String expected = "{\"id\":\"\\\\d+\"}"; // Expected contains regex pattern

103

String actual = "{\"id\":\"12345\"}"; // Actual contains value to match

104

JSONAssert.assertEquals(expected, actual,

105

new CustomComparator(JSONCompareMode.LENIENT,

106

new Customization("id", dynamicMatcher)));

107

```

108

109

### Array Value Matcher

110

111

Specialized matcher for arrays that provides flexible element-by-element comparison with support for partial matching, index-specific validation, and repeating patterns.

112

113

```java { .api }

114

public class ArrayValueMatcher<T> implements LocationAwareValueMatcher<T> {

115

/**

116

* Match every element in actual array against expected array pattern.

117

*

118

* @param comparator comparator to use for element comparison

119

*/

120

public ArrayValueMatcher(JSONComparator comparator);

121

122

/**

123

* Match specific element in actual array against first element of expected.

124

*

125

* @param comparator comparator to use for element comparison

126

* @param index index of the array element to be compared

127

*/

128

public ArrayValueMatcher(JSONComparator comparator, int index);

129

130

/**

131

* Match elements in specified range against expected array pattern.

132

*

133

* @param comparator comparator to use for element comparison

134

* @param from first element index to compare (inclusive)

135

* @param to last element index to compare (inclusive)

136

*/

137

public ArrayValueMatcher(JSONComparator comparator, int from, int to);

138

139

public boolean equal(T o1, T o2);

140

public boolean equal(String prefix, T actual, T expected, JSONCompareResult result);

141

}

142

```

143

144

**Usage Examples:**

145

146

```java

147

// Validate all array elements have same structure

148

JSONComparator elementComparator = new DefaultComparator(JSONCompareMode.LENIENT);

149

ArrayValueMatcher<Object> allElementsMatcher = new ArrayValueMatcher<>(elementComparator);

150

151

// Expected pattern (will be repeated for each actual element)

152

String expected = "{\"users\":[{\"active\":true}]}";

153

String actual = "{\"users\":[{\"active\":true,\"id\":1},{\"active\":true,\"id\":2}]}";

154

155

Customization arrayCustomization = new Customization("users", allElementsMatcher);

156

CustomComparator comparator = new CustomComparator(JSONCompareMode.LENIENT, arrayCustomization);

157

JSONAssert.assertEquals(expected, actual, comparator);

158

159

// Validate specific array element

160

ArrayValueMatcher<Object> firstElementMatcher = new ArrayValueMatcher<>(elementComparator, 0);

161

Customization firstElementCustomization = new Customization("items", firstElementMatcher);

162

163

// Validate range of elements

164

ArrayValueMatcher<Object> rangeMatcher = new ArrayValueMatcher<>(elementComparator, 1, 3);

165

Customization rangeCustomization = new Customization("products", rangeMatcher);

166

167

// Complex array validation with regex

168

int arrayLength = 4; // known array length

169

RegularExpressionValueMatcher<Object> idMatcher = new RegularExpressionValueMatcher<>("\\\\d+");

170

Customization[] idCustomizations = new Customization[arrayLength];

171

for (int i = 0; i < arrayLength; i++) {

172

idCustomizations[i] = new Customization("items[" + i + "].id", idMatcher);

173

}

174

CustomComparator idComparator = new CustomComparator(JSONCompareMode.STRICT_ORDER, idCustomizations);

175

ArrayValueMatcher<Object> idArrayMatcher = new ArrayValueMatcher<>(idComparator);

176

```

177

178

### Path-Based Customization

179

180

Associates custom matchers with specific JSON paths using pattern matching with wildcards and path expressions.

181

182

```java { .api }

183

public class Customization {

184

/**

185

* Create customization for specific JSON path.

186

*

187

* @param path JSON path pattern (supports *, **, wildcards)

188

* @param comparator value matcher for this path

189

*/

190

public Customization(String path, ValueMatcher<Object> comparator);

191

192

/**

193

* Factory method for creating customizations.

194

*/

195

public static Customization customization(String path, ValueMatcher<Object> comparator);

196

197

/**

198

* Check if customization applies to given path.

199

*/

200

public boolean appliesToPath(String path);

201

202

/**

203

* Test if values match using this customization's matcher.

204

*

205

* @deprecated Use matches(String, Object, Object, JSONCompareResult)

206

*/

207

@Deprecated

208

public boolean matches(Object actual, Object expected);

209

210

/**

211

* Test values with location awareness and result reporting.

212

*/

213

public boolean matches(String prefix, Object actual, Object expected, JSONCompareResult result)

214

throws ValueMatcherException;

215

}

216

```

217

218

**Path Pattern Examples:**

219

220

```java

221

// Exact path match

222

new Customization("user.name", matcher);

223

224

// Wildcard for any single field name

225

new Customization("users.*.active", matcher);

226

227

// Double wildcard for any nested path

228

new Customization("**.email", matcher);

229

230

// Array element patterns

231

new Customization("items[0].id", matcher);

232

new Customization("users[*].roles[*]", matcher);

233

234

// Complex patterns

235

new Customization("data.**.validation.*.result", matcher);

236

```

237

238

### Value Matcher Exception

239

240

Exception for custom error messages from value matchers.

241

242

```java { .api }

243

public class ValueMatcherException extends RuntimeException {

244

public ValueMatcherException(String message, String expected, String actual);

245

public ValueMatcherException(String message, Throwable cause, String expected, String actual);

246

247

public String getExpected();

248

public String getActual();

249

}

250

```

251

252

**Usage Examples:**

253

254

```java

255

ValueMatcher<Object> rangeValidator = new ValueMatcher<Object>() {

256

@Override

257

public boolean equal(Object actual, Object expected) {

258

if (actual instanceof Number && expected instanceof Number) {

259

double actualVal = ((Number) actual).doubleValue();

260

double expectedVal = ((Number) expected).doubleValue();

261

262

if (Math.abs(actualVal - expectedVal) > 0.01) {

263

throw new ValueMatcherException(

264

"Values differ by more than 0.01",

265

expected, actual

266

);

267

}

268

return true;

269

}

270

return Objects.equals(actual, expected);

271

}

272

};

273

```

274

275

## Advanced Usage Patterns

276

277

### Combining Multiple Customizations

278

279

```java

280

// Multiple field-specific matchers

281

Customization emailCustomization = new Customization("**.email",

282

new RegularExpressionValueMatcher<>("^[\\w._%+-]+@[\\w.-]+\\.[A-Z]{2,}$"));

283

284

Customization phoneCustomization = new Customization("**.phone",

285

new RegularExpressionValueMatcher<>("^\\+?[1-9]\\d{1,14}$"));

286

287

Customization nameCustomization = new Customization("**.name",

288

new ValueMatcher<Object>() {

289

public boolean equal(Object o1, Object o2) {

290

return o1.toString().equalsIgnoreCase(o2.toString());

291

}

292

});

293

294

CustomComparator multiCustomComparator = new CustomComparator(

295

JSONCompareMode.LENIENT,

296

emailCustomization,

297

phoneCustomization,

298

nameCustomization

299

);

300

```

301

302

### Array Element Validation

303

304

```java

305

// Validate array structure with different matchers per field

306

DefaultComparator baseComparator = new DefaultComparator(JSONCompareMode.LENIENT);

307

308

// Create customizations for ID validation within array elements

309

RegularExpressionValueMatcher<Object> uuidMatcher =

310

new RegularExpressionValueMatcher<>("^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$");

311

312

Customization idValidation = new Customization("items.*.id", uuidMatcher);

313

CustomComparator elementComparator = new CustomComparator(JSONCompareMode.LENIENT, idValidation);

314

315

// Apply to all array elements

316

ArrayValueMatcher<Object> arrayMatcher = new ArrayValueMatcher<>(elementComparator);

317

Customization arrayCustomization = new Customization("items", arrayMatcher);

318

319

CustomComparator finalComparator = new CustomComparator(JSONCompareMode.LENIENT, arrayCustomization);

320

321

String expected = "{\"items\":[{\"id\":\"PLACEHOLDER\",\"name\":\"test\"}]}";

322

String actual = "{\"items\":[{\"id\":\"550e8400-e29b-41d4-a716-446655440000\",\"name\":\"test\"}]}";

323

324

JSONAssert.assertEquals(expected, actual, finalComparator);

325

```