or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

api-comparison-diffing.mdcore-osgi-processing.mdheader-processing.mdindex.mdjar-resource-management.mdplugin-architecture.mdrepository-system.mdversion-management.mdworkspace-project-management.md

api-comparison-diffing.mddocs/

0

# API Comparison and Diffing

1

2

Semantic versioning analysis based on API changes between bundle versions, enabling automated compatibility assessment and version recommendation.

3

4

## Capabilities

5

6

### DiffImpl

7

8

Implementation for comparing APIs between JAR versions and detecting breaking changes.

9

10

```java { .api }

11

/**

12

* Implementation for comparing APIs between JAR versions

13

*/

14

public class DiffImpl implements Diff {

15

/** Compare two JAR files and generate diff */

16

public Diff diff(Jar newer, Jar older) throws Exception;

17

18

/** Create API tree from JAR */

19

public Tree tree(Jar jar) throws Exception;

20

21

/** Get diff instructions for filtering */

22

public Instructions getDiffInstructions();

23

24

/** Set diff instructions */

25

public void setDiffInstructions(Instructions instructions);

26

27

/** Check if change is ignored */

28

public boolean isIgnored(Element element);

29

30

/** Get diff reporter */

31

public Reporter getReporter();

32

33

/** Set diff reporter */

34

public void setReporter(Reporter reporter);

35

}

36

37

/**

38

* Represents a difference between API elements

39

*/

40

public interface Diff {

41

/** Get diff type */

42

public Delta getDelta();

43

44

/** Get element type */

45

public Element getType();

46

47

/** Get element name */

48

public String getName();

49

50

/** Get children diffs */

51

public Collection<? extends Diff> getChildren();

52

53

/** Get newer element */

54

public Element getNewer();

55

56

/** Get older element */

57

public Element getOlder();

58

}

59

60

/**

61

* Types of changes detected

62

*/

63

public enum Delta {

64

IGNORE, // Change should be ignored

65

UNCHANGED, // No change

66

MINOR, // Minor change (backward compatible)

67

MAJOR, // Major change (breaking)

68

MICRO, // Micro change (implementation only)

69

ADDED, // New element added

70

REMOVED // Element removed

71

}

72

```

73

74

**Usage Examples:**

75

76

```java

77

import aQute.bnd.differ.DiffImpl;

78

import aQute.bnd.differ.Diff;

79

import aQute.bnd.differ.Delta;

80

81

// Compare two versions of a bundle

82

Jar newer = new Jar(new File("mybundle-2.0.0.jar"));

83

Jar older = new Jar(new File("mybundle-1.0.0.jar"));

84

85

DiffImpl differ = new DiffImpl();

86

Diff diff = differ.diff(newer, older);

87

88

// Analyze changes

89

analyzeDiff(diff, 0);

90

91

// Helper method to analyze diff recursively

92

private void analyzeDiff(Diff diff, int indent) {

93

String prefix = " ".repeat(indent);

94

Delta delta = diff.getDelta();

95

96

System.out.println(prefix + delta + ": " + diff.getType() + " " + diff.getName());

97

98

// Process child diffs

99

for (Diff child : diff.getChildren()) {

100

analyzeDiff(child, indent + 1);

101

}

102

}

103

```

104

105

### Baseline

106

107

Performs semantic versioning analysis based on API changes and recommends appropriate version increments.

108

109

```java { .api }

110

/**

111

* Performs semantic versioning analysis based on API changes

112

*/

113

public class Baseline {

114

/** Create baseline analyzer */

115

public Baseline(Reporter reporter, Instructions diffignore);

116

117

/** Perform baseline analysis */

118

public Set<Info> baseline(Jar jar, Jar baseline, Instructions instructions) throws Exception;

119

120

/** Get suggested version */

121

public Version getSuggestedVersion();

122

123

/** Check if baseline passed */

124

public boolean isOk();

125

126

/** Get baseline errors */

127

public List<String> getErrors();

128

129

/** Get baseline warnings */

130

public List<String> getWarnings();

131

}

132

133

/**

134

* Baseline information for a package

135

*/

136

public class Info implements Comparable<Info> {

137

/** Get package name */

138

public String packageName;

139

140

/** Get suggested version */

141

public Version suggestedVersion;

142

143

/** Get newer version */

144

public Version newerVersion;

145

146

/** Get older version */

147

public Version olderVersion;

148

149

/** Get version change type */

150

public Delta delta;

151

152

/** Get warnings */

153

public List<String> warnings;

154

155

/** Check if version is too low */

156

public boolean mismatch;

157

158

/** Get attributes */

159

public Attrs attributes;

160

}

161

```

162

163

**Usage Examples:**

164

165

```java

166

import aQute.bnd.differ.Baseline;

167

import aQute.bnd.differ.Baseline.Info;

168

import aQute.bnd.build.Instructions;

169

170

// Perform baseline analysis

171

Jar current = new Jar(new File("current.jar"));

172

Jar previous = new Jar(new File("previous.jar"));

173

174

Reporter reporter = new ConsoleReporter();

175

Instructions diffIgnore = new Instructions();

176

diffIgnore.put("*impl*", new Attrs()); // Ignore implementation packages

177

178

Baseline baseline = new Baseline(reporter, diffIgnore);

179

Set<Info> results = baseline.baseline(current, previous, new Instructions());

180

181

// Analyze results

182

for (Info info : results) {

183

System.out.println("Package: " + info.packageName);

184

System.out.println(" Current version: " + info.newerVersion);

185

System.out.println(" Previous version: " + info.olderVersion);

186

System.out.println(" Suggested version: " + info.suggestedVersion);

187

System.out.println(" Change type: " + info.delta);

188

189

if (info.mismatch) {

190

System.out.println(" WARNING: Version too low for changes detected");

191

}

192

193

for (String warning : info.warnings) {

194

System.out.println(" WARNING: " + warning);

195

}

196

}

197

198

// Check overall result

199

if (baseline.isOk()) {

200

System.out.println("Baseline analysis passed");

201

System.out.println("Suggested bundle version: " + baseline.getSuggestedVersion());

202

} else {

203

System.err.println("Baseline analysis failed");

204

for (String error : baseline.getErrors()) {

205

System.err.println("ERROR: " + error);

206

}

207

}

208

```

209

210

### Element Hierarchy

211

212

Classes representing different elements in the API tree for diff analysis.

213

214

```java { .api }

215

/**

216

* Base class for API elements

217

*/

218

public abstract class Element {

219

/** Get element type */

220

public abstract Type getType();

221

222

/** Get element name */

223

public abstract String getName();

224

225

/** Get element key for comparison */

226

public String getKey();

227

228

/** Get element version */

229

public Version getVersion();

230

231

/** Get element attributes */

232

public Map<String, String> getAttributes();

233

234

/** Compare with another element */

235

public Delta compare(Element other);

236

}

237

238

/**

239

* Types of API elements

240

*/

241

public enum Type {

242

ROOT,

243

BUNDLE,

244

PACKAGE,

245

CLASS,

246

INTERFACE,

247

ANNOTATION,

248

ENUM,

249

METHOD,

250

CONSTRUCTOR,

251

FIELD,

252

CONSTANT

253

}

254

255

/**

256

* Java-specific element for class analysis

257

*/

258

public class JavaElement extends Element {

259

/** Get Java access modifiers */

260

public int getAccess();

261

262

/** Check if element is public */

263

public boolean isPublic();

264

265

/** Check if element is protected */

266

public boolean isProtected();

267

268

/** Check if element is static */

269

public boolean isStatic();

270

271

/** Check if element is final */

272

public boolean isFinal();

273

274

/** Check if element is abstract */

275

public boolean isAbstract();

276

277

/** Get method signature */

278

public String getSignature();

279

280

/** Get return type */

281

public String getReturnType();

282

283

/** Get parameter types */

284

public String[] getParameterTypes();

285

286

/** Get exception types */

287

public String[] getExceptionTypes();

288

}

289

```

290

291

### Diff Instructions

292

293

Configuration for controlling diff analysis and ignoring specific changes.

294

295

```java { .api }

296

/**

297

* Instructions for controlling diff analysis

298

*/

299

public class Instructions extends LinkedHashMap<Instruction, Attrs> {

300

/** Create empty instructions */

301

public Instructions();

302

303

/** Create from properties */

304

public Instructions(Properties properties);

305

306

/** Check if element matches any instruction */

307

public boolean matches(String name);

308

309

/** Get instruction that matches name */

310

public Instruction getMatching(String name);

311

312

/** Add instruction */

313

public Instruction put(String pattern, Attrs attributes);

314

315

/** Get all patterns */

316

public Set<String> getPatterns();

317

}

318

319

/**

320

* Single instruction with pattern and attributes

321

*/

322

public class Instruction {

323

/** Get instruction pattern */

324

public String getPattern();

325

326

/** Get instruction attributes */

327

public Attrs getAttributes();

328

329

/** Check if pattern matches string */

330

public boolean matches(String value);

331

332

/** Check if instruction is literal (no wildcards) */

333

public boolean isLiteral();

334

335

/** Check if instruction is negated */

336

public boolean isNegated();

337

}

338

```

339

340

### Repository Diff Utilities

341

342

Utilities for comparing repository contents and tracking changes over time.

343

344

```java { .api }

345

/**

346

* Repository difference analyzer

347

*/

348

public class RepositoryDiff {

349

/** Compare two repositories */

350

public static Diff compareRepositories(Repository newer, Repository older) throws Exception;

351

352

/** Find changed bundles between repositories */

353

public static Map<String, Diff> findChangedBundles(Repository newer, Repository older) throws Exception;

354

355

/** Generate compatibility report */

356

public static CompatibilityReport generateReport(Repository newer, Repository older) throws Exception;

357

}

358

359

/**

360

* Compatibility report between repository versions

361

*/

362

public class CompatibilityReport {

363

/** Get added bundles */

364

public Set<String> getAddedBundles();

365

366

/** Get removed bundles */

367

public Set<String> getRemovedBundles();

368

369

/** Get changed bundles */

370

public Map<String, BundleChange> getChangedBundles();

371

372

/** Get compatibility summary */

373

public CompatibilitySummary getSummary();

374

}

375

376

/**

377

* Change information for a bundle

378

*/

379

public class BundleChange {

380

public String bundleSymbolicName;

381

public Version oldVersion;

382

public Version newVersion;

383

public Delta overallChange;

384

public Map<String, Delta> packageChanges;

385

public List<String> breakingChanges;

386

public List<String> warnings;

387

}

388

```

389

390

**Complete API Comparison Example:**

391

392

```java

393

import aQute.bnd.differ.*;

394

import aQute.bnd.build.Instructions;

395

396

// Complete API comparison and baseline workflow

397

public class APIComparisonWorkflow {

398

399

public void performAPIAnalysis(File currentBundle, File previousBundle) throws Exception {

400

try (Jar current = new Jar(currentBundle);

401

Jar previous = new Jar(previousBundle)) {

402

403

// Step 1: Perform detailed diff analysis

404

DiffImpl differ = new DiffImpl();

405

Diff diff = differ.diff(current, previous);

406

407

System.out.println("=== API Diff Analysis ===");

408

printDiffTree(diff, 0);

409

410

// Step 2: Perform baseline analysis for version recommendations

411

Reporter reporter = new Reporter() {

412

public void error(String msg, Object... args) {

413

System.err.println("ERROR: " + String.format(msg, args));

414

}

415

public void warning(String msg, Object... args) {

416

System.err.println("WARNING: " + String.format(msg, args));

417

}

418

public void progress(float progress, String msg, Object... args) {

419

System.out.println("PROGRESS: " + String.format(msg, args));

420

}

421

};

422

423

// Configure what to ignore in baseline

424

Instructions diffIgnore = new Instructions();

425

diffIgnore.put("*impl*", new Attrs()); // Ignore impl packages

426

diffIgnore.put("*.internal.*", new Attrs()); // Ignore internal packages

427

428

Baseline baseline = new Baseline(reporter, diffIgnore);

429

Set<Baseline.Info> baselineResults = baseline.baseline(current, previous, new Instructions());

430

431

System.out.println("\n=== Baseline Analysis ===");

432

for (Baseline.Info info : baselineResults) {

433

System.out.println("Package: " + info.packageName);

434

System.out.println(" Previous: " + info.olderVersion + " -> Current: " + info.newerVersion);

435

System.out.println(" Suggested: " + info.suggestedVersion);

436

System.out.println(" Change: " + info.delta);

437

438

if (info.mismatch) {

439

System.out.println(" ❌ Version mismatch - version too low for detected changes");

440

}

441

442

for (String warning : info.warnings) {

443

System.out.println(" ⚠️ " + warning);

444

}

445

}

446

447

// Step 3: Generate summary and recommendations

448

System.out.println("\n=== Summary ===");

449

if (baseline.isOk()) {

450

System.out.println("βœ… Baseline analysis passed");

451

Version suggested = baseline.getSuggestedVersion();

452

if (suggested != null) {

453

System.out.println("πŸ“¦ Recommended bundle version: " + suggested);

454

}

455

} else {

456

System.out.println("❌ Baseline analysis failed");

457

for (String error : baseline.getErrors()) {

458

System.out.println(" " + error);

459

}

460

}

461

462

// Step 4: Generate compatibility report

463

generateCompatibilityReport(diff, baselineResults);

464

}

465

}

466

467

private void printDiffTree(Diff diff, int level) {

468

String indent = " ".repeat(level);

469

Delta delta = diff.getDelta();

470

471

String icon = getChangeIcon(delta);

472

System.out.println(indent + icon + " " + diff.getType() + " " + diff.getName());

473

474

for (Diff child : diff.getChildren()) {

475

printDiffTree(child, level + 1);

476

}

477

}

478

479

private String getChangeIcon(Delta delta) {

480

switch (delta) {

481

case ADDED: return "βž•";

482

case REMOVED: return "❌";

483

case MAJOR: return "πŸ’₯";

484

case MINOR: return "πŸ”„";

485

case MICRO: return "πŸ”§";

486

case UNCHANGED: return "βœ…";

487

default: return "❓";

488

}

489

}

490

491

private void generateCompatibilityReport(Diff diff, Set<Baseline.Info> baselineResults) {

492

System.out.println("\n=== Compatibility Report ===");

493

494

// Count changes by type

495

Map<Delta, Integer> changeCounts = new HashMap<>();

496

countChanges(diff, changeCounts);

497

498

System.out.println("Change Summary:");

499

for (Map.Entry<Delta, Integer> entry : changeCounts.entrySet()) {

500

if (entry.getValue() > 0) {

501

System.out.println(" " + entry.getKey() + ": " + entry.getValue());

502

}

503

}

504

505

// Compatibility assessment

506

boolean hasBreaking = changeCounts.getOrDefault(Delta.MAJOR, 0) > 0 ||

507

changeCounts.getOrDefault(Delta.REMOVED, 0) > 0;

508

509

if (hasBreaking) {

510

System.out.println("⚠️ BREAKING CHANGES DETECTED");

511

System.out.println(" This release contains breaking changes that may affect consumers");

512

} else {

513

System.out.println("βœ… BACKWARD COMPATIBLE");

514

System.out.println(" This release maintains backward compatibility");

515

}

516

}

517

518

private void countChanges(Diff diff, Map<Delta, Integer> counts) {

519

Delta delta = diff.getDelta();

520

counts.put(delta, counts.getOrDefault(delta, 0) + 1);

521

522

for (Diff child : diff.getChildren()) {

523

countChanges(child, counts);

524

}

525

}

526

}

527

```