Skip to content
All work

Case study 01 / 03

Smart Duplicate Detector

  • Java
  • Maven
  • Node.js
  • npm

A static-analysis tool that finds duplicated logic in Java code. It compares the shape of each method, not its text, so renamed variables and reformatting don't hide a copy.

Role
Lead developer (35 of the project's 40 commits)
Year
2026
Team
3 engineers, course project
Stack
Java 17, JavaParser, Weighted Levenshtein, Swing + FlatLaf, Javalin, Maven, Node.js CLI wrapper
The desktop app after a scan, listing structurally similar methods with their scores
The desktop app after a scan, listing structurally similar methods with their scores
The project website with the npm install command
The project website with the npm install command

Problem

Duplicated business logic creeps into Java projects through copy-paste, AI-generated code and parallel implementations. The copies drift apart, so a bug fixed in one stays live in the other. Text-based duplicate finders either miss these copies, because names and formatting changed, or flood you with false positives from getters, setters and imports.

Constraints

  • Java 17 and an object-oriented design were course requirements.
  • It had to work both for a developer at a terminal and for someone who prefers a window and buttons.
  • Every method is compared with every other method, so cost grows with the square of the method count.

Architecture

  1. Project scanner

    finds every .java file

  2. AST parser

    JavaParser → node-type tokens

  3. Similarity engine

    weighted Levenshtein

  4. Reports

    desktop app · CLI · Javalin API

Each method becomes a list of AST node types (IfStmt, ForStmt, MethodCallExpr…). Names never enter the comparison, which is why renaming a variable doesn't hide a duplicate.

Key decisions

  1. Trade-off 1

    I chose comparing AST node types over comparing source text or tokens, because names and formatting change between copies, but the structure of the logic doesn't.

  2. Trade-off 2

    I chose a weighted edit distance (control flow ×10, method calls ×2) over plain Levenshtein, because a different if or loop changes what a method does far more than an extra variable declaration.

  3. Trade-off 3

    I chose shipping the JAR inside an npm package with a small Node.js launcher over a Maven-only release, because `npm i -g` is one command most developers already have, and the launcher checks for Java 17 first with a clear error.

What I built

  • The scanning and detection pipeline: file discovery, AST extraction with JavaParser, and the weighted similarity algorithm.
  • A filter that skips methods with fewer than three statements, which removes getters and setters from the results.
  • A Swing desktop app with a FlatLaf dark theme, an adjustable similarity threshold and background scanning via SwingWorker.
  • A CLI (`sdd --path . --threshold 0.75`), published to npm as `smart-duplicate-detector`, plus a small Javalin API.
  • Unit tests for the scoring and an end-to-end integration test that scans real files in a temporary directory.

Result

  • Published on npm in July 2026; 207 downloads from July to October 2026, according to npm's public download stats.

What I'd do next

  • Group methods by size and structure hash before comparing, so large projects avoid the all-pairs cost.
  • Output SARIF so results show up inline in GitHub code scanning and IDEs.
  • Add a refactoring hint for each pair: the shared logic that could be extracted.

Want something like this built?