RepoPilotOpen in app →

alibaba/HandyJSON

A handy swift json-object serialization/deserialization library

Mixed

Stale — last commit 2y ago

worst of 4 axes
Use as dependencyConcerns

non-standard license (Other); last commit was 2y ago

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • 15 active contributors
  • Distributed ownership (top contributor 42% of recent commits)
  • Other licensed
Show 4 more →
  • CI configured
  • Tests present
  • Stale — last commit 2y ago
  • Non-standard license (Other) — review terms
What would change the summary?
  • Use as dependency ConcernsMixed if: clarify license terms

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/alibaba/handyjson?axis=fork)](https://repopilot.app/r/alibaba/handyjson)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/alibaba/handyjson on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: alibaba/HandyJSON

Generated by RepoPilot · 2026-05-10 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/alibaba/HandyJSON shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Stale — last commit 2y ago

  • 15 active contributors
  • Distributed ownership (top contributor 42% of recent commits)
  • Other licensed
  • CI configured
  • Tests present
  • ⚠ Stale — last commit 2y ago
  • ⚠ Non-standard license (Other) — review terms

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live alibaba/HandyJSON repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/alibaba/HandyJSON.

What it runs against: a local clone of alibaba/HandyJSON — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in alibaba/HandyJSON | Confirms the artifact applies here, not a fork | | 2 | License is still Other | Catches relicense before you depend on it | | 3 | Default branch master exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 823 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>alibaba/HandyJSON</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of alibaba/HandyJSON. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/alibaba/HandyJSON.git
#   cd HandyJSON
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of alibaba/HandyJSON and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "alibaba/HandyJSON(\\.git)?\\b" \\
  && ok "origin remote is alibaba/HandyJSON" \\
  || miss "origin remote is not alibaba/HandyJSON (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
  && ok "license is Other" \\
  || miss "license drift — was Other at generation time"

# 3. Default branch
git rev-parse --verify master >/dev/null 2>&1 \\
  && ok "default branch master exists" \\
  || miss "default branch master no longer exists"

# 4. Critical files exist
test -f "Source/Deserializer.swift" \\
  && ok "Source/Deserializer.swift" \\
  || miss "missing critical file: Source/Deserializer.swift"
test -f "Source/Serializer.swift" \\
  && ok "Source/Serializer.swift" \\
  || miss "missing critical file: Source/Serializer.swift"
test -f "Source/Metadata.swift" \\
  && ok "Source/Metadata.swift" \\
  || miss "missing critical file: Source/Metadata.swift"
test -f "Source/PropertyInfo.swift" \\
  && ok "Source/PropertyInfo.swift" \\
  || miss "missing critical file: Source/PropertyInfo.swift"
test -f "Source/ReflectionHelper.swift" \\
  && ok "Source/ReflectionHelper.swift" \\
  || miss "missing critical file: Source/ReflectionHelper.swift"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 823 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~793d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/alibaba/HandyJSON"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

HandyJSON is a Swift framework that serializes and deserializes pure Swift classes and structs to/from JSON without requiring NSObject inheritance or explicit mapping functions. It uses Swift runtime reflection and direct memory layout manipulation to automatically convert objects to dictionaries, JSON strings, and vice versa—supporting optional types, enums, dates, nested objects, and inheritance chains. Flat structure: Source/ contains ~35 Swift files organized by concern (Deserializer.swift, DataTransform.swift, EnumTransform.swift, FieldDescriptor.swift, Metadata.swift) plus support for basic/bridge/custom types. HandyJSONDemo/ is a working iOS app example. Tests live in .xcscheme targets (iOS/macOS/tvOS/watchOS Tests).

👥Who it's for

iOS/macOS/tvOS/watchOS Swift developers who need lightweight JSON serialization without the boilerplate of Codable protocols or manual mapping, particularly those building Alibaba-scale mobile apps requiring fast, reflection-based model binding.

🌱Maturity & risk

Production-ready and actively maintained. The codebase is ~290KB of Swift with CI/CD via Travis CI (see .travis.yml), CocoaPods/Carthage/SPM support, and version 5.0.4-beta addressing iOS 15 crashes. Recent updates to the CHANGELOG and structured test suites (across iOS/macOS/tvOS/watchOS schemes) indicate active development.

Significant risk: HandyJSON depends entirely on Swift runtime memory layout implementation details (as stated in README: 'totally depend on the memory layout rules infered from Swift runtime code'), meaning it breaks with Swift compiler changes—evidenced by the iOS 15 beta3 crash fix. Single maintainer (Alibaba) increases abandonment risk. No visible open PR/issue data in this snapshot, but the monolithic Source/ directory suggests tight coupling.

Active areas of work

Fixing iOS 15 compatibility (version 5.0.4-beta announced in README). CHANGELOG and Package.swift versioning suggest incremental releases. No recent commit date visible in provided data, but active CocoaPods/Carthage integration and multi-platform scheme maintenance indicate ongoing support.

🚀Get running

git clone https://github.com/alibaba/HandyJSON.git && cd HandyJSON && open HandyJSON.xcodeproj (or pod install if using CocoaPods). Run via Xcode schemes (HandyJSON iOS Tests, HandyJSON macOS Tests, etc.) or swift build (SPM support via Package.swift).

Daily commands: Xcode: select scheme (HandyJSON iOS, HandyJSON macOS, etc.) and press Cmd+R. SPM: swift build. CocoaPods: pod install then xcodebuild. See HandyJSONDemo/ViewController.swift for runnable deserialization/serialization examples.

🗺️Map of the codebase

  • Source/Deserializer.swift — Core deserialization engine that converts JSON to Swift objects via reflection and direct memory manipulation.
  • Source/Serializer.swift — Core serialization engine that converts Swift objects to JSON by reading memory layout and property values.
  • Source/Metadata.swift — Swift runtime metadata introspection layer that extracts type information and field descriptors for reflection.
  • Source/PropertyInfo.swift — Property descriptor and accessor layer that handles field type checking, offset calculation, and value access.
  • Source/ReflectionHelper.swift — Helper utilities for runtime reflection including type checking, field enumeration, and memory layout querying.
  • Source/Transformable.swift — Protocol definition for JSON transformable types; the main public API for adopting serialization/deserialization.
  • Source/TransformType.swift — Base protocol and concrete implementations for value transformation during serialization/deserialization.

🛠️How to make changes

Add Support for a Custom Type (with Transform)

  1. Create a new TransformType conformance in a new file (e.g., Source/MyCustomTransform.swift) that implements transform(fromJSON:) and transform(toJSON:). (Source/TransformType.swift)
  2. In your model class/struct, add a property with @Transform<MyCustomTransform> annotation or return it from HelpingMapper.mappingForJSON(). (Source/HelpingMapper.swift)
  3. Test your transform in Tests/HandyJSONTests/CustomTransformTest.swift following existing pattern. (Tests/HandyJSONTests/CustomTransformTest.swift)

Add a New Built-in Type Handler

  1. If it's a standard Swift type, add serialization logic to Source/BuiltInBasicType.swift. (Source/BuiltInBasicType.swift)
  2. If it's an Objective-C bridged type, add logic to Source/BuiltInBridgeType.swift instead. (Source/BuiltInBridgeType.swift)
  3. Add corresponding deserialization case in Source/Deserializer.swift's deserializeValue() function. (Source/Deserializer.swift)
  4. Add test cases in Tests/HandyJSONTests/BasicTypesInClassTestsFromJSON.swift and ToJSON variant. (Tests/HandyJSONTests/BasicTypesInClassTestsFromJSON.swift)

Customize JSON Field Mapping and Transformation

  1. In your model class/struct, adopt HelpingMapper protocol and implement mappingForJSON() to define field name mappings. (Source/HelpingMapper.swift)
  2. In mappingForJSON(), return a mapping dictionary where key is Swift property name and value is JSON key name; optionally chain TransformType via handyTransform parameter. (Source/HelpingMapper.swift)
  3. Alternatively, use @Transform<T> property wrapper with your custom TransformType conformance (requires Source/TransformOf.swift or similar). (Source/TransformOf.swift)
  4. Test your mapping in Tests/HandyJSONTests/CustomMappingTest.swift. (Tests/HandyJSONTests/CustomMappingTest.swift)

Enable Serialization for a New Model Type

  1. Define your Swift class or struct (no NSObject inheritance required). (Source/Transformable.swift)
  2. Conform your type to HandyJSON protocol by adding empty conformance or implementing optional methods from Transformable.swift. (Source/Transformable.swift)
  3. Call model.toJSON() to serialize or ModelClass.deserialize(from: jsonDict) to deserialize; HandyJSON will use reflection to walk properties. (Source/Serializer.swift)
  4. If you need custom mapping, implement HelpingMapper protocol in your model. (Source/HelpingMapper.swift)

🔧Why these technologies

  • Swift Runtime Reflection (Swift ABI) — Avoids NSObject and KVC overhead; enables direct property introspection on pure Swift types via memory layout.
  • Direct Memory Writes (Unsafe Pointers) — Bypasses property setters for performance; writes deserialized values directly to object memory at computed field offsets.
  • C FFI for Runtime Metadata — Swift runtime is not publicly exposed; CBridge.swift bridges to C runtime structures to read type descriptors.
  • TransformType Protocol — Pluggable value transformation adapters; decouples custom serialization logic from core engine.
  • HelpingMapper Protocol — Optional custom field mapping and filtering; allows model classes to define JSON key aliases without inheritance.

⚖️Trade-offs already made

  • Direct memory writes instead of property setters

    • Why: Extreme performance and avoiding boilerplate property initialization code.
    • Consequence: Bypasses didSet/willSet observers and computed properties; models must use stored properties and simple initialization.
  • No NSObject inheritance requirement

    • Why: Simpler model definitions; no KVC overhead; pure Swift classes/structs.
    • Consequence: Tightly coupled to Swift runtime ABI; breaks if Apple changes memory

🪤Traps & gotchas

  1. Memory layout dependency: code assumes specific Swift ABI—if you upgrade Swift compiler, runtime crashes may occur (see iOS 15 beta3 fix). 2) No explicit namespace: HandyJSON extends protocols globally via extensions (Export.swift), risking conflicts if other libraries define HandyJSON protocol. 3) Direct memory writes in deserialization bypass Swift's safety checks—corrupted JSON can cause memory unsafety. 4) Enum support requires specific Transform implementation; generic enums may silently fail. 5) Inheritance chains require parent struct/class to also conform to HandyJSON protocol; missing parent conformance breaks child deserialization.

🏗️Architecture

💡Concepts to learn

  • Swift Runtime Metadata & Type Reflection — HandyJSON's entire mechanism relies on reading type information from the Swift runtime (FieldDescriptor, Metadata) at runtime to dynamically map JSON fields to object properties—understanding this is essential to debugging deserialization failures
  • Memory Layout & Direct Pointer Writes — HandyJSON writes deserialized values directly to memory offsets (found via FieldDescriptor) rather than using KVC or property setters—this is why it's fast but risky; a learner must understand pointer arithmetic and memory safety implications
  • Symbol Name Mangling (Demangling) — Swift mangles internal symbol names in the binary; MangledName.swift reverses this to match JSON keys to runtime property names—critical for reflection-based mapping to work correctly across compiler versions
  • Struct vs. Class Memory Layout Differences — HandyJSON treats structs and classes differently due to different memory layouts (value vs. reference semantics); FieldDescriptor and pointer calculations must account for this, and errors cause silent failures or crashes
  • Protocol Composition & Generic Transforms — DataTransform protocol allows type-specific serialization behavior (e.g., DateTransform, EnumTransform); understanding how to extend this is key to supporting custom types
  • Objective-C Runtime Bridging — CBridge.swift bridges to Objective-C runtime functions to access Swift metadata not exposed in public Swift API—understanding this boundary is critical when porting to new Swift versions
  • JSON to Type Inference & Nested Deserialization — HelpingMapper.swift must recursively infer types for nested objects and collections from metadata; this recursive process with optional unwrapping is where most deserialization bugs occur
  • SwiftyJSON/SwiftyJSON — Alternative JSON parsing for Swift that focuses on safe dictionary navigation rather than direct deserialization to typed models
  • Moya/Moya — Networking abstraction layer commonly used with HandyJSON for JSON API response mapping in iOS apps
  • realm/realm-swift — Database layer often paired with HandyJSON for object-to-JSON-to-Realm synchronization in data-driven apps
  • alibaba/Tangram-iOS — Sister Alibaba project for card-based layouts; heavily uses HandyJSON for component configuration deserialization

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive tests for CustomDateFormatTransform and ISO8601DateTransform

The repo has DateTransform.swift, DateFormatterTransform.swift, CustomDateFormatTransform.swift, and ISO8601DateTransform.swift in Source/, but Tests/HandyJSONTests/ lacks dedicated test files for these date transformation features. This is critical since date serialization/deserialization is a common source of bugs and timezone-related issues.

  • [ ] Create Tests/HandyJSONTests/DateTransformTests.swift covering DateTransform, DateFormatterTransform, CustomDateFormatTransform, and ISO8601DateTransform
  • [ ] Add test cases for various date formats, timezones, and edge cases (leap years, DST transitions)
  • [ ] Test deserialization from JSON with malformed dates to ensure graceful error handling
  • [ ] Verify that custom date formats work correctly in both nested models and arrays

Add tests for EnumTransform and Enum types serialization/deserialization

Source/ contains EnumTransform.swift and EnumType.swift, but there are no dedicated test files for enum handling. Given that enums are a key Swift language feature and require special reflection handling, comprehensive tests are essential to prevent regressions.

  • [ ] Create Tests/HandyJSONTests/EnumTransformTests.swift
  • [ ] Add tests for raw value enums (String, Int), associated value enums, and nested enums
  • [ ] Test enum deserialization with invalid/unknown cases to verify error handling
  • [ ] Add tests for enums in arrays, optionals, and complex model hierarchies

Add tests for CustomBasicType and custom model type extensions

Source/ExtendCustomBasicType.swift and Source/ExtendCustomModelType.swift exist but have no corresponding test coverage in Tests/. These extensions enable users to support custom types, and lacking tests makes it difficult for contributors to safely refactor the reflection logic without breaking this feature.

  • [ ] Create Tests/HandyJSONTests/CustomTypeExtensionTests.swift
  • [ ] Add test cases demonstrating how to extend HandyJSON for custom basic types (UUID, URL variants, custom structs)
  • [ ] Add tests for custom model type transformations and composition scenarios
  • [ ] Include tests validating that custom types work correctly in collections and optional properties

🌿Good first issues

  • Add test coverage for Source/EnumTransform.swift—currently no visible tests for enum deserialization edge cases (e.g., associated values, raw values with custom types)
  • Document and test Source/ExtendCustomModelType.swift and Source/ExtendCustomBasicType.swift—README lacks examples for extending HandyJSON to custom types; add runnable examples
  • Implement warning/error logging in Source/Logger.swift for silent failures—currently fails silently on mismatched field types; add structured logging to aid debugging

Top contributors

Click to expand

📝Recent commits

Click to expand
  • f0b15db — 5.0.4-beta podspec (chantu.lhl)
  • 6414e41 — 5.0.4-beta & update readme (chantu.lhl)
  • 7e3b212 — fix properties in OC super class cannot parse (chantu.lhl)
  • 4971b12 — import foundation (chantu.lhl)
  • 785a627 — iOS 15 beta crash bug fix (chantu.lhl)
  • f07a7a8 — Revert "iOS 15 crash fix" (chantu.lhl)
  • b277068 — iOS 15 crash fix (chantu.lhl)
  • 379f6ac — update podspec to 5.0.3-beta & update readme (chantu)
  • e3d3659 — Merge pull request #397 from mewehk/master (H. Li)
  • 7d4a974 — fix iOS 14 beta 4 crash (mewehk)

🔒Security observations

HandyJSON presents moderate to high security concerns due to its fundamental architecture of direct memory manipulation and reflection-based access without safety guarantees. The library's core design bypasses Swift's type safety and access control mechanisms to achieve performance and ease of use, which inherently creates attack surface. While suitable for trusted data sources, it poses significant risks when deserializing untrusted JSON from external sources. Critical issues include unsafe memory access, lack of input validation, and absence of bounds checking. Recommendations include adding comprehensive input validation, respecting access control, implementing memory safety checks, and enforcing strict type validation throughout the deserialization pipeline.

  • High · Direct Memory Layout Dependency Without Validation — Source/Metadata.swift, Source/ReflectionHelper.swift, Source/Properties.swift, Source/FieldDescriptor.swift. HandyJSON relies directly on Swift runtime memory layout rules for serialization/deserialization without validation. The README explicitly states 'totally depend on the memory layout rules infered from Swift runtime code.' This creates a vulnerability where changes to Swift runtime internals, compiler optimizations, or unsafe memory access patterns could lead to undefined behavior, memory corruption, or type confusion attacks. Fix: Implement memory bounds checking, validate type information before dereferencing, add runtime assertions for memory layout assumptions, and consider using safer Swift APIs. Add comprehensive fuzzing tests for malformed input data.
  • High · Unsafe Reflection and Direct Memory Writing — Source/Deserializer.swift, Source/PropertyInfo.swift. The library writes values directly to memory addresses without comprehensive validation: 'writing value to memory directly to achieve property assignment'. This bypasses normal type safety checks and could allow attackers to manipulate object state through crafted JSON payloads, potentially leading to privilege escalation or arbitrary code execution. Fix: Implement strict type validation before memory writes, add checks for buffer overflows, validate that target addresses are within expected object bounds, and audit all direct memory manipulation code paths.
  • Medium · Missing Input Validation for JSON Data — Source/Deserializer.swift. The deserialization process lacks explicit input validation for JSON source data. There is no visible validation for extremely large inputs, deeply nested structures, or malformed data that could cause DoS through memory exhaustion or stack overflow. Fix: Implement size limits for JSON payloads, add depth limits for nested structures, validate input before processing, and add timeout mechanisms for deserialization operations.
  • Medium · Reflection-Based Access Without Access Control — Source/ReflectionHelper.swift, Source/Properties.swift. The use of Swift reflection to access and modify private and internal properties bypasses Swift's access control mechanisms. This allows JSON data to set private fields that should be protected. Fix: Respect Swift's access control modifiers, only allow deserialization to public properties, document the behavior clearly, and consider adding configuration options to enforce stricter access control.
  • Medium · No Type Checking for Transform Operations — Source/CustomDateFormatTransform.swift, Source/EnumTransform.swift, Source/TransformType.swift, Source/TransformOf.swift. Custom transform implementations (DateFormatterTransform, EnumTransform, etc.) may not validate input types before transformation, potentially allowing type confusion or invalid casting that could crash the application or cause undefined behavior. Fix: Add explicit type checking before all transform operations, validate transform output, implement error handling for invalid transformations, and add unit tests for edge cases and invalid inputs.
  • Low · Deprecated or Unspecified Minimum Swift Version — .swift-version, Package@swift-4.swift. The .swift-version file exists but its contents are not provided. The project supports older Swift versions which may lack security fixes. The Package@swift-4.swift suggests legacy Swift 4 support. Fix: Document and enforce a minimum Swift version that receives active security updates, consider deprecating support for Swift versions older than 5.1, and require users to use modern toolchains.
  • Low · Insufficient Error Handling — Source/Deserializer.swift, Source/Serializer.swift. The codebase lacks visible comprehensive error handling documentation and examples. Failed deserialization or memory operations could silently produce invalid objects or crash. Fix: Implement explicit error types, add comprehensive error handling and recovery mechanisms, provide clear error messages for debugging, and add error handling examples in documentation.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · alibaba/HandyJSON — RepoPilot