Skip to content

Allow multiple @JacksonInject targets for same id (#5217)#5609

Open
dlwldnjs1009 wants to merge 13 commits intoFasterXML:3.xfrom
dlwldnjs1009:fix/5217-duplicate-injectable-value
Open

Allow multiple @JacksonInject targets for same id (#5217)#5609
dlwldnjs1009 wants to merge 13 commits intoFasterXML:3.xfrom
dlwldnjs1009:fix/5217-duplicate-injectable-value

Conversation

@dlwldnjs1009
Copy link
Copy Markdown
Contributor

@dlwldnjs1009 dlwldnjs1009 commented Jan 25, 2026

This PR changes injectable collection to allow multiple injection targets for the same id (#5217).

Behavioral goal (#5217)

  • Remove the inconsistency where field-field could fail with "Duplicate injectable value" while creator-param injection fails due to missing InjectableValues. After this change, errors are consistent across field/param cases.

Implementation

API compatibility (revised per review feedback)

  • BeanDescription#findInjectables() signature restored to Map<Object, AnnotatedMember> and deprecated.
  • New BeanDescription#findAllInjectables() added as a concrete default method returning Map<Object, List<AnnotatedMember>>.
    This avoids breaking custom BeanDescription implementations that only override the legacy method.
  • POJOPropertiesCollector#getInjectables() deprecated; new getAllInjectables() added.
  • Internal caller (BeanDeserializerFactory) switched to findAllInjectables().

Complexity reduction (revised per review feedback)

Tests


Revised per review feedback from @cowtowncoder.

dlwldnjs1009 and others added 5 commits January 25, 2026 14:35
Switch injectables map value to List<AnnotatedMember> to support multiple
@JacksonInject targets for same id.

Keep existing masking rules (creator param masks same-property members, setter
masks field) and add explicit failure for setter-setter conflicts on same
property/id. Add memoized member->property lookup + tests.
Verify field-field and param-param don't fail with "Duplicate injectable
value" error when InjectableValues is not configured. This directly tests
the original issue's expected behavior: consistent error across all cases.
Verify field-field and param-param both throw MissingInjectableValueExcepion
(same exception type), proving error path convergence per issue's expected
behavior: "The same error should be made in all cases."
- testRecordWithRenamedInjectableProperty: record with renamed injectable
- testRecordRenamedPlusDifferentFieldBothInjected: renamed creator + different
  property field with same ID should both be injected
@github-actions
Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 80.24% 📈 +0.040%
Branches branches 73.26% 📈 +0.020%

Coverage data generated from JaCoCo test results

}

public Map<Object, AnnotatedMember> getInjectables() {
public Map<Object, List<AnnotatedMember>> getInjectables() {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is, technically speaking, incompatible API change.

For compatibility we probably need to add new method (with different name since cannot overload) (getAllInjectables()?) with simple implementation but then re-implement old "old" version which needs to take and return first value of List members. Old version should be deprecated.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, this can't work due to compatibility issue At least AS-IS.

return;
}
for (POJOPropertyBuilder creatorProp : _creatorProperties) {
if (creatorProp == null) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this happen?

*/

public abstract Map<Object, AnnotatedMember> findInjectables();
public abstract Map<Object, List<AnnotatedMember>> findInjectables();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ouch. And even here we have API change... same approach.

@cowtowncoder
Copy link
Copy Markdown
Member

Hmmh. Good job figuring out how to make this work.

My main concern is the whole addition of complexity and additional significant extra-processing. Almost to the degree I wonder if it's all worth it, or if different re-factoring/rethinking was needed.

I'll have to think about this; probably should want after 3.1 at this point.

@github-actions
Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 80.24% 📈 +0.040%
Branches branches 73.25% 📈 +0.010%

Coverage data generated from JaCoCo test results

@dlwldnjs1009
Copy link
Copy Markdown
Contributor Author

dlwldnjs1009 commented Jan 27, 2026

@cowtowncoder
Minor note (separate from this PR):

I noticed the exception class name MissingInjectableValueExcepion (missing the “t” in “Exception”).
File: src/main/java/tools/jackson/databind/exc/MissingInjectableValueExcepion.java

I didn’t change it here since renaming would be a public API change.
If you’d like, I can open a follow-up issue/PR to discuss a backward-compatible path
(e.g., add a correctly named alias, deprecate the old name, and migrate gradually).

…asterXML#4218)

- Restore findInjectables() signature to Map<Object, AnnotatedMember>
  with @deprecated; add findAllInjectables() as concrete default method
- Remove _deduplicateSamePropertyInjectables (setter-masks-field policy)
  and _isMethod helper to reduce complexity per review feedback
- Keep only _removeCreatorPropertyInjectables for FasterXML#4218 fix
- Add getAllInjectables() / getInjectables() pair on POJOPropertiesCollector
  with defensive copy and freeze of value lists
- Switch BeanDeserializerFactory to findAllInjectables()
- Add default-id field-field regression, behavior, and API shape tests
- Remove Rule 2 tests (testFieldAndSetterSameProperty etc.)
@github-actions
Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 80.18% 📉 -0.030%
Branches branches 73.18% 📉 -0.090%

Coverage data generated from JaCoCo test results

@cowtowncoder
Copy link
Copy Markdown
Member

@cowtowncoder Minor note (separate from this PR):

I noticed the exception class name MissingInjectableValueExcepion (missing the “t” in “Exception”). File: src/main/java/tools/jackson/databind/exc/MissingInjectableValueExcepion.java

I didn’t change it here since renaming would be a public API change. If you’d like, I can open a follow-up issue/PR to discuss a backward-compatible path (e.g., add a correctly named alias, deprecate the old name, and migrate gradually).

Ah. I think I must have noticed it at some point but not before 3.0 release.

Yes, a separate PR would be make sense, targeting 3.x (for 3.1), creating correctly named sub-class (I think?) exception, deprecating misspelled one and so on.

@github-actions
Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 80.18% 📉 -0.030%
Branches branches 73.18% 📉 -0.090%

Coverage data generated from JaCoCo test results

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 4, 2026

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 80.38% 📉 -0.030%
Branches branches 73.47% 📉 -0.090%

Coverage data generated from JaCoCo test results

@github-actions
Copy link
Copy Markdown

github-actions bot commented Feb 8, 2026

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 80.85% 📉 -0.040%
Branches branches 74.01% 📉 -0.110%

Coverage data generated from JaCoCo test results

@github-actions
Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 80.98% 📉 -0.030%
Branches branches 74.10% 📉 -0.090%

Coverage data generated from JaCoCo test results

@github-actions
Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 81.24% 📉 -0.040%
Branches branches 74.34% 📉 -0.080%

Coverage data generated from JaCoCo test results

@github-actions
Copy link
Copy Markdown

🧪 Code Coverage Report

Metric Coverage Change
Instructions coverage 81.33% 📉 -0.030%
Branches branches 74.54% 📉 -0.090%

Coverage data generated from JaCoCo test results

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants