본문으로 건너뛰기
cccskills
무료GitHub에 공개

diagnose

Use when a test fails and you need to diagnose the root cause. Run the test, read errors, trace through generated and source code, fix, and verify.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

설치 방법 보기

포함된 파일(1)

  • SKILL.md7.0 KB

SKILL.md(원문)

설치하기 전에 에이전트에게 전달되는 지시 내용을 확인할 수 있습니다.

Diagnose Test Failure

Overview

Systematic diagnosis of test failures in the Morphia project. Run the test, read the full error, trace the root cause through source and generated code, fix minimally, and verify.

Workflow

  1. Run the failing test

    ./mvnw test -pl :module-name -Dtest="ClassName#methodName" -Ddeploy.skip=true
    
    • Use -Ddeploy.skip=true to skip dokka
    • Do NOT use -am with -Dtest= (applies test filter to all modules)
    • If dependencies need rebuilding first:
      ./mvnw install -pl :dep1,:dep2 -DskipTests -Ddeploy.skip=true -Dinvoker.skip=true
      
  2. Read the full error - stack trace, error message, line numbers. Don't skip anything.

  3. Find relevant code - Read both source AND generated code:

    • Source: src/main/, src/test/
    • Generated bytecode: target/test-classes/ - use javap -c -p ClassName to decompile
    • Generated sources: target/generated-sources/
    • Interfaces from dependencies: check ~/.m2/repository/ source jars with unzip -p
  4. Trace the root cause - Follow the error backward:

    • What method is missing/wrong?
    • What generated it? All critter bytecode comes from the Class-File API generators in core/src/main/java/dev/morphia/critter/parser/generator/ (see "Critter Code Generation" below).
    • Was it the AOT path (critter-maven, woven __read*/__write* methods) or the runtime path (hidden nestmate accessors)?
    • What does the interface/superclass require?
    • Compare with a working generator for the same pattern (e.g. how PropertyAccessorGenerator boxes primitives)
  5. Fix minimally - One change at a time. Rebuild affected modules:

    ./mvnw install -pl :morphia-core,:critter-maven -DskipTests -Ddeploy.skip=true -Dinvoker.skip=true
    
  6. Verify - Re-run the failing test AND related tests in the same class.

Critter Code Generation

Critter generates bytecode with the Class-File API (java.lang.classfile), using the jdk-classfile-backport library (package io.smallrye.classfile) so it runs on Java 17. There is no Gizmo or ASM in the generators. Everything is in core/src/main/java/dev/morphia/critter/parser/generator/, and CritterGenerator is the entry point.

GeneratorProduces
AddFieldAccessorMethods / AddMethodAccessorMethodsAOT only: rewrites the entity class to add synthetic __readXxx/__writeXxx methods
PropertyAccessorGeneratorAOT only: a PropertyAccessor that calls the woven __read*/__write* methods
NestmateAccessorGeneratorRuntime only: a PropertyAccessor using direct getfield/putfield/invokevirtual, defined as a hidden nestmate (Lookup.defineHiddenClass(..., NESTMATE)) and registered in NestmateAccessorRegistry
PropertyModelGeneratorA CritterPropertyModel per property
EntityModelGeneratorThe CritterEntityModel for the entity
VarHandleAccessorGeneratorA VarHandle/MethodHandle-based accessor; not used by the main pipeline right now (only TestVarHandleAccessor)

The two paths:

  • AOT: critter-maven (generate-models / generate-test-models) calls CritterGenerator.generate(type, loader, false). It writes the generated models and the woven entity classes to disk under __morphia/<entity>/.
  • Runtime: when no pre-generated model is on the classpath, CritterMapper calls generate(type, loader, true). That defines classes in a CritterClassLoader plus hidden nestmates. If it fails, it logs once and falls back to a reflective EntityModel. Hidden nestmates need full privilege access, so an entity outside Morphia's module (on the classpath: loaded by a different class loader) fails with a NestmateAccessException; CritterMapper logs a specific "can't access ... isn't in Morphia's module" warning for it. That's expected for those layouts, and the fix is critter-maven AOT models, not a generator change.

PropertyFinder rejects some entities for AOT with UnsupportedOperationException("AOT skip: ..."): inherited fields the entity can't reach and whose declaring class can't be rewritten (e.g. a private field in a library superclass), fields shadowing a superclass field, array-typed fields, and entities whose @Id is on a getter. Entities with no @Id at all (e.g., embedded types) are generated normally. A final field's __writeXxx sets it through a cached java.lang.reflect.Field, since putfield may only write a final field from a constructor. An inherited field from a superclass in the same output directory or jar gets its __readXxx/__writeXxx methods woven into that superclass, which the entity inherits. The rejected entities use runtime generation instead, so an "AOT skip" warning in the critter-maven output is expected for them and is not an error.

Common Morphia/Critter Issues

ErrorLikely Cause
AbstractMethodErrorA generated class is missing an interface method. Generators emit methods with explicit erased descriptors (e.g. get(Ljava/lang/Object;)Ljava/lang/Object;), and nothing adds bridge methods for you
VerifyError / Bad type on operand stackUsually a primitive/reference mismatch: a primitive was used where an Object was expected, or the reverse, without boxing or unboxing
ClassCastException in a generated accessorcheckcast to the wrong owner (for an inherited field, the declaring class vs the entity class) or to the wrong wrapper type
IllegalAccessError from a nestmate accessorThe hidden class was defined against the wrong lookup class. It must be privateLookupIn the field's declaring class
NoSuchMethodError __read*/__write*The AOT accessor ran against an unwoven entity class, e.g. the woven class from generated-classes/critter is not ahead of the original on the classpath
ClassNotFoundException __morphia.*Critter code generation didn't run or class not registered

Key Gotchas

  • The Class-File API is low-level: no automatic boxing, casting, or bridge methods. Emit each step explicitly.
  • Boxing: invokestatic Wrapper.valueOf(prim)Wrapper. Unboxing: checkcast Wrapper, then invokevirtual Wrapper.xxxValue(). Helpers live in GenerationUtils (PRIMITIVE_TO_WRAPPER, primitiveUnboxMethod, primitiveClassDesc).
  • checkcast only accepts reference types. To get a primitive from an Object, cast to the wrapper and then unbox.
  • Keep non-public types out of generated descriptors. AOT accessors use Object in __read*/__write* signatures for reference types, and the cast happens inside the entity.
  • Inspect generated classes with javap -c -p. AOT output is under target/generated-classes/critter (main) or target/test-classes/**/__morphia/ (tests). Runtime-generated classes are in memory only.

리뷰

아직 리뷰가 없습니다. 사용해 본 소감을 남겨 주세요.

댓글

로그인 없이 쓸 수 있습니다. 사용 후기, 질문, 작동하지 않은 환경 등을 편하게 남겨 주세요.

아직 댓글이 없습니다. 첫 댓글을 남겨 보세요.

보내면 바로 공개됩니다. 이메일 주소나 전화번호 같은 개인 정보는 쓰지 마세요. URL은 2개까지입니다.

0 / 1,000자

이 양식은 reCAPTCHA로 보호되며 Google 개인정보처리방침 및 서비스 약관이 적용됩니다.

같은 저장소의 스킬

Build and test the Morphia project using Maven. Use when compiling, running tests, or building artifacts.

한국어 요약은 준비 중입니다. 원문 설명을 표시하고 있습니다.

MorphiaOrg/morphia1.7천2026년 10월 20일 업데이트

MorphiaOrg의 스킬 모두 보기

이 스킬의 문제 신고