Repository: open-feature/java-sdk
Pull request #663 (2023-10-23 20:29:54)

fix: null handling with Structure, Value
* fix NPEs with Structure.asObjectMap and Structure.convertValue
* more consistent null handling in structures (empty `Value` -> `null` and vice versa)
* update spotbugs and fix a few new detected issues

sonarcloud[bot]: SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=663)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [![B](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/B-16px.png 'B')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [1 Code Smell](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list)



![idea](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png 'idea') Catch issues before they fail your Quality Gate with our IDE extension ![sonarlint](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png 'sonarlint') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=sonarcloud-welcome)
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/open-feature/java-sdk/pull/663?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature) Report
> Merging [#663](https://app.codecov.io/gh/open-feature/java-sdk/pull/663?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature) (e3da4c1) into [main](https://app.codecov.io/gh/open-feature/java-sdk/commit/fe5a20f2c39c776a68f5533ee950b96adf548231?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature) (fe5a20f) will **increase** coverage by `0.25%`.
> The diff coverage is `80.00%`.

```diff
@@             Coverage Diff              @@
##               main     #663      +/-   ##
============================================
+ Coverage     94.47%   94.73%   +0.25%     
- Complexity      362      366       +4     
============================================
  Files            32       32              
  Lines           851      854       +3     
  Branches         51       52       +1     
============================================
+ Hits            804      809       +5     
+ Misses           24       23       -1     
+ Partials         23       22       -1     
```

| [Flag](https://app.codecov.io/gh/open-feature/java-sdk/pull/663/flags?src=pr&el=flags&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature) | Coverage Δ | |
|---|---|---|
| [unittests](https://app.codecov.io/gh/open-feature/java-sdk/pull/663/flags?src=pr&el=flag&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature) | `94.73% <80.00%> (+0.25%)` | :arrow_up: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Files](https://app.codecov.io/gh/open-feature/java-sdk/pull/663?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature) | Coverage Δ | |
|---|---|---|
| [...n/java/dev/openfeature/sdk/ImmutableStructure.java](https://app.codecov.io/gh/open-feature/java-sdk/pull/663?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature#diff-c3JjL21haW4vamF2YS9kZXYvb3BlbmZlYXR1cmUvc2RrL0ltbXV0YWJsZVN0cnVjdHVyZS5qYXZh) | `100.00% <100.00%> (ø)` | |
| [src/main/java/dev/openfeature/sdk/Value.java](https://app.codecov.io/gh/open-feature/java-sdk/pull/663?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature#diff-c3JjL21haW4vamF2YS9kZXYvb3BlbmZlYXR1cmUvc2RrL1ZhbHVlLmphdmE=) | `91.07% <100.00%> (+0.98%)` | :arrow_up: |
| [src/main/java/dev/openfeature/sdk/Structure.java](https://app.codecov.io/gh/open-feature/java-sdk/pull/663?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature#diff-c3JjL21haW4vamF2YS9kZXYvb3BlbmZlYXR1cmUvc2RrL1N0cnVjdHVyZS5qYXZh) | `86.66% <50.00%> (-1.71%)` | :arrow_down: |

... and [1 file with indirect coverage changes](https://app.codecov.io/gh/open-feature/java-sdk/pull/663/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature)

:mega: We’re building smart automated test selection to slash your CI/CD build times. [Learn more](https://about.codecov.io/iterative-testing/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=open-feature)

sonarcloud[bot]: SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=663)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [![B](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/B-16px.png 'B')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [1 Code Smell](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list)



![idea](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png 'idea') Catch issues before they fail your Quality Gate with our IDE extension ![sonarlint](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png 'sonarlint') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=sonarcloud-welcome)
sonarcloud[bot]: SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=663)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [![B](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/B-16px.png 'B')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [1 Code Smell](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list)



![idea](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png 'idea') Catch issues before they fail your Quality Gate with our IDE extension ![sonarlint](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png 'sonarlint') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=sonarcloud-welcome)
sonarcloud[bot]: SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=663)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [![B](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/B-16px.png 'B')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [1 Code Smell](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list)



![idea](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png 'idea') Catch issues before they fail your Quality Gate with our IDE extension ![sonarlint](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png 'sonarlint') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=sonarcloud-welcome)
sonarcloud[bot]: SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=663)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [![B](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/B-16px.png 'B')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [1 Code Smell](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list)



![idea](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png 'idea') Catch issues before they fail your Quality Gate with our IDE extension ![sonarlint](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png 'sonarlint') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=sonarcloud-welcome)
sonarcloud[bot]: SonarCloud Quality Gate failed.&nbsp; &nbsp; [![Quality Gate failed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/failed-16px.png 'Quality Gate failed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=663)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [![B](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/B-16px.png 'B')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [1 Code Smell](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list)



![idea](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/light_bulb-16px.png 'idea') Catch issues before they fail your Quality Gate with our IDE extension ![sonarlint](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/sonarlint-16px.png 'sonarlint') [SonarLint](https://www.sonarsource.com/products/sonarlint/features/connected-mode/?referrer=sonarcloud-welcome)
sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=663)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [3 Code Smells](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=663)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [3 Code Smells](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!&nbsp; &nbsp; [![Quality Gate passed](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/QualityGateBadge/passed-16px.png 'Quality Gate passed')](https://sonarcloud.io/dashboard?id=open-feature_java-sdk&pullRequest=663)

[![Bug](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug-16px.png 'Bug')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=BUG)  
[![Vulnerability](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability-16px.png 'Vulnerability')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=VULNERABILITY)  
[![Security Hotspot](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot-16px.png 'Security Hotspot')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=SECURITY_HOTSPOT)  
[![Code Smell](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell-16px.png 'Code Smell')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [![A](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A-16px.png 'A')](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL) [3 Code Smells](https://sonarcloud.io/project/issues?id=open-feature_java-sdk&pullRequest=663&resolved=false&types=CODE_SMELL)

[![No Coverage information](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo-16px.png 'No Coverage information')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663) No Coverage information  
[![0.0%](https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3-16px.png '0.0%')](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=open-feature_java-sdk&pullRequest=663&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/pom.xml b/pom.xml
index f283528..d2fbe95 100644
--- a/pom.xml
+++ b/pom.xml
@@ -53,7 +53,7 @@
       <!-- used so that lombok can generate suppressions for spotbugs. It needs to find it on the relevant classpath -->
       <groupId>com.github.spotbugs</groupId>
       <artifactId>spotbugs</artifactId>
-      <version>4.7.3</version>
+      <version>4.8.0</version>
       <scope>provided</scope>
     </dependency>
 
@@ -365,7 +365,7 @@
           <dependency>
             <groupId>com.github.spotbugs</groupId>
             <artifactId>spotbugs</artifactId>
-            <version>4.7.3</version>
+            <version>4.8.0</version>
           </dependency>
         </dependencies>
         <executions>
diff --git a/spotbugs-exclusions.xml b/spotbugs-exclusions.xml
index 8105db9..66032ad 100644
--- a/spotbugs-exclusions.xml
+++ b/spotbugs-exclusions.xml
@@ -26,6 +26,26 @@
         <Class name="dev.openfeature.sdk.OpenFeatureAPI"/>
         <Bug pattern="EI_EXPOSE_REP2"/>
     </And>
+    <And>
+        Added in spotbugs 4.8.0 - EventProvider shares a name with something from the standard lib (confusing), but change would be breaking
+        <Class name="dev.openfeature.sdk.EventProvider"/>
+        <Bug pattern="PI_DO_NOT_REUSE_PUBLIC_IDENTIFIERS_CLASS_NAMES"/>
+    </And>
+    <And>
+        Added in spotbugs 4.8.0 - Metadata shares a name with something from the standard lib (confusing), but change would be breaking
+        <Class name="dev.openfeature.sdk.Metadata"/>
+        <Bug pattern="PI_DO_NOT_REUSE_PUBLIC_IDENTIFIERS_CLASS_NAMES"/>
+    </And>
+    <And>
+        Added in spotbugs 4.8.0 - Reason shares a name with something from the standard lib (confusing), but change would be breaking
+        <Class name="dev.openfeature.sdk.Reason"/>
+        <Bug pattern="PI_DO_NOT_REUSE_PUBLIC_IDENTIFIERS_CLASS_NAMES"/>
+    </And>
+    <And>
+        Added in spotbugs 4.8.0 - FlagValueType.STRING shares a name with something from the standard lib (confusing), but change would be breaking
+        <Class name="dev.openfeature.sdk.FlagValueType"/>
+        <Bug pattern="PI_DO_NOT_REUSE_PUBLIC_IDENTIFIERS_FIELD_NAMES"/>
+    </And>
 
     <!-- Test class that should be excluded -->
     <Match>
diff --git a/src/main/java/dev/openfeature/sdk/AbstractStructure.java b/src/main/java/dev/openfeature/sdk/AbstractStructure.java
new file mode 100644
index 0000000..a7d7c2e
--- /dev/null
+++ b/src/main/java/dev/openfeature/sdk/AbstractStructure.java
@@ -0,0 +1,35 @@
+package dev.openfeature.sdk;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@SuppressWarnings({ "PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType" })
+abstract class AbstractStructure implements Structure {
+
+    protected final Map<String, Value> attributes;
+
+    AbstractStructure() {
+        this.attributes = new HashMap<>();
+    }
+
+    AbstractStructure(Map<String, Value> attributes) {
+        this.attributes = attributes;
+    }
+
+    /**
+     * Get all values as their underlying primitives types.
+     *
+     * @return all attributes on the structure into a Map
+     */
+    @Override
+    public Map<String, Object> asObjectMap() {
+        return attributes
+                .entrySet()
+                .stream()
+                // custom collector, workaround for Collectors.toMap in JDK8
+                // https://bugs.openjdk.org/browse/JDK-8148463
+                .collect(HashMap::new,
+                        (accumulated, entry) -> accumulated.put(entry.getKey(), convertValue(entry.getValue())),
+                        HashMap::putAll);
+    }
+}
diff --git a/src/main/java/dev/openfeature/sdk/ImmutableStructure.java b/src/main/java/dev/openfeature/sdk/ImmutableStructure.java
index 731a55b..7ea1ef6 100644
--- a/src/main/java/dev/openfeature/sdk/ImmutableStructure.java
+++ b/src/main/java/dev/openfeature/sdk/ImmutableStructure.java
@@ -1,32 +1,32 @@
 package dev.openfeature.sdk;
 
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Map;
+import java.util.Optional;
 import java.util.Set;
-import java.util.stream.Collectors;
+
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
 
 /**
- * {@link ImmutableStructure} represents a potentially nested object type which is used to represent
+ * {@link ImmutableStructure} represents a potentially nested object type which
+ * is used to represent
  * structured data.
- * The ImmutableStructure is a Structure implementation which is threadsafe, and whose attributes can
- * not be modified after instantiation.
+ * The ImmutableStructure is a Structure implementation which is threadsafe, and
+ * whose attributes can
+ * not be modified after instantiation. All references are clones.
  */
 @ToString
 @EqualsAndHashCode
-@SuppressWarnings({"PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType"})
-public final class ImmutableStructure implements Structure {
-
-    private final Map<String, Value> attributes;
+@SuppressWarnings({ "PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType" })
+public final class ImmutableStructure extends AbstractStructure {
 
     /**
      * create an immutable structure with the empty attributes.
      */
     public ImmutableStructure() {
-        this(new HashMap<>());
+        super();
     }
 
     /**
@@ -35,10 +35,14 @@ public final class ImmutableStructure implements Structure {
      * @param attributes attributes.
      */
     public ImmutableStructure(Map<String, Value> attributes) {
-        Map<String, Value> copy = attributes.entrySet()
+        super(new HashMap<>(attributes.entrySet()
                 .stream()
-                .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue().clone()));
-        this.attributes = new HashMap<>(copy);
+                .collect(HashMap::new,
+                        (accumulated, entry) -> accumulated.put(entry.getKey(),
+                                Optional.ofNullable(entry.getValue())
+                                    .map(e -> e.clone())
+                                    .orElse(null)),
+                        HashMap::putAll)));
     }
 
     @Override
@@ -63,25 +67,11 @@ public final class ImmutableStructure implements Structure {
         return attributes
                 .entrySet()
                 .stream()
-                .collect(Collectors.toMap(
-                        Map.Entry::getKey,
-                        e -> getValue(e.getKey())
-                ));
-    }
-
-    /**
-     * Get all values, with primitives types.
-     *
-     * @return all attributes on the structure into a Map
-     */
-    @Override
-    public Map<String, Object> asObjectMap() {
-        return attributes
-                .entrySet()
-                .stream()
-                .collect(Collectors.toMap(
-                        Map.Entry::getKey,
-                        e -> convertValue(getValue(e.getKey()))
-                ));
+                .collect(HashMap::new,
+                        (accumulated, entry) -> accumulated.put(entry.getKey(),
+                                Optional.ofNullable(entry.getValue())
+                                .map(e -> e.clone())
+                                .orElse(null)),
+                        HashMap::putAll);
     }
 }
diff --git a/src/main/java/dev/openfeature/sdk/MutableStructure.java b/src/main/java/dev/openfeature/sdk/MutableStructure.java
index 343fe2c..3c4f34d 100644
--- a/src/main/java/dev/openfeature/sdk/MutableStructure.java
+++ b/src/main/java/dev/openfeature/sdk/MutableStructure.java
@@ -1,14 +1,13 @@
 package dev.openfeature.sdk;
 
-import lombok.EqualsAndHashCode;
-import lombok.ToString;
-
 import java.time.Instant;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
-import java.util.stream.Collectors;
+
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
 
 /**
  * {@link MutableStructure} represents a potentially nested object type which is used to represent 
@@ -19,16 +18,14 @@ import java.util.stream.Collectors;
 @ToString
 @EqualsAndHashCode
 @SuppressWarnings({"PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType"})
-public class MutableStructure implements Structure {
-
-    protected final Map<String, Value> attributes;
+public class MutableStructure extends AbstractStructure {
 
     public MutableStructure() {
-        this.attributes = new HashMap<>();
+        super();
     }
 
     public MutableStructure(Map<String, Value> attributes) {
-        this.attributes = new HashMap<>(attributes);
+        super(attributes);
     }
 
     @Override
@@ -92,20 +89,4 @@ public class MutableStructure implements Structure {
     public Map<String, Value> asMap() {
         return new HashMap<>(this.attributes);
     }
-
-    /**
-     * Get all values, with primitives types.
-     *
-     * @return all attributes on the structure into a Map
-     */
-    @Override
-    public Map<String, Object> asObjectMap() {
-        return attributes
-            .entrySet()
-            .stream()
-            .collect(Collectors.toMap(
-                Map.Entry::getKey,
-                e -> convertValue(getValue(e.getKey()))
-            ));
-    }
 }
diff --git a/src/main/java/dev/openfeature/sdk/Structure.java b/src/main/java/dev/openfeature/sdk/Structure.java
index 46274e7..6ceaf59 100644
--- a/src/main/java/dev/openfeature/sdk/Structure.java
+++ b/src/main/java/dev/openfeature/sdk/Structure.java
@@ -48,12 +48,17 @@ public interface Structure {
     Map<String, Object> asObjectMap();
 
     /**
-     * convertValue is converting the object type Value in a primitive type.
+     * Converts the Value into its equivalent primitive type.
      *
      * @param value - Value object to convert
-     * @return an Object containing the primitive type.
+     * @return an Object containing the primitive type, or null.
      */
     default Object convertValue(Value value) {
+
+        if (value == null || value.isNull()) {
+            return null;
+        }
+
         if (value.isBoolean()) {
             return value.asBoolean();
         }
@@ -85,15 +90,14 @@ public interface Structure {
         if (value.isStructure()) {
             Structure s = value.asStructure();
             return s.asMap()
-                    .keySet()
+                    .entrySet()
                     .stream()
-                    .collect(
-                            Collectors.toMap(
-                                    key -> key,
-                                    key -> convertValue(s.getValue(key))
-                            )
-                    );
+                    .collect(HashMap::new,
+                            (accumulated, entry) -> accumulated.put(entry.getKey(),
+                                    convertValue(entry.getValue())),
+                            HashMap::putAll);
         }
+
         throw new ValueNotConvertableError();
     }
 
@@ -134,7 +138,9 @@ public interface Structure {
      */
     static Structure mapToStructure(Map<String, Object> map) {
         return new MutableStructure(map.entrySet().stream()
-            .filter(e -> e.getValue() != null)
-            .collect(Collectors.toMap(Map.Entry::getKey, e -> objectToValue(e.getValue()))));
+            .collect(HashMap::new,
+                        (accumulated, entry) -> accumulated.put(entry.getKey(),
+                        objectToValue(entry.getValue())),
+                        HashMap::putAll));
     }
 }
diff --git a/src/main/java/dev/openfeature/sdk/Value.java b/src/main/java/dev/openfeature/sdk/Value.java
index 8be5017..59e4a9c 100644
--- a/src/main/java/dev/openfeature/sdk/Value.java
+++ b/src/main/java/dev/openfeature/sdk/Value.java
@@ -19,11 +19,15 @@ import static dev.openfeature.sdk.Structure.mapToStructure;
  */
 @ToString
 @EqualsAndHashCode
-@SuppressWarnings({"PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType"})
+@SuppressWarnings({"PMD.BeanMembersShouldSerialize", "checkstyle:MissingJavadocType", "checkstyle:NoFinalizer"})
 public class Value implements Cloneable {
 
     private final Object innerObject;
 
+    protected final void finalize() {
+        // DO NOT REMOVE, spotbugs: CT_CONSTRUCTOR_THROW
+    }
+
     /**
      * Construct a new null Value.
      */
@@ -271,11 +275,7 @@ public class Value implements Cloneable {
             return new Value(copy);
         }
         if (this.isStructure()) {
-            Map<String, Value> copy = this.asStructure().asMap().entrySet().stream().collect(Collectors.toMap(
-                    Map.Entry::getKey,
-                    e -> e.getValue().clone()
-            ));
-            return new Value(new ImmutableStructure(copy));
+            return new Value(new ImmutableStructure(this.asStructure().asMap()));
         }
         if (this.isInstant()) {
             Instant copy = Instant.ofEpochMilli(this.asInstant().toEpochMilli());
@@ -294,7 +294,7 @@ public class Value implements Cloneable {
         if (object instanceof Value) {
             return (Value) object;
         } else if (object == null) {
-            return null;
+            return new Value();
         } else if (object instanceof String) {
             return new Value((String) object);
         } else if (object instanceof Boolean) {


Test patch:
diff --git a/src/test/java/dev/openfeature/sdk/ImmutableStructureTest.java b/src/test/java/dev/openfeature/sdk/ImmutableStructureTest.java
index d745345..491b506 100644
--- a/src/test/java/dev/openfeature/sdk/ImmutableStructureTest.java
+++ b/src/test/java/dev/openfeature/sdk/ImmutableStructureTest.java
@@ -122,4 +122,11 @@ class ImmutableStructureTest {
 
         assertEquals(expected, structure.asObjectMap());
     }
+
+    @Test
+    void constructorHandlesNullValue() {
+        HashMap<String, Value> attrs = new HashMap<>();
+        attrs.put("null", null);
+        new ImmutableStructure(attrs);
+    }
 }
diff --git a/src/test/java/dev/openfeature/sdk/StructureTest.java b/src/test/java/dev/openfeature/sdk/StructureTest.java
index 8f18891..16747ee 100644
--- a/src/test/java/dev/openfeature/sdk/StructureTest.java
+++ b/src/test/java/dev/openfeature/sdk/StructureTest.java
@@ -98,6 +98,20 @@ public class StructureTest {
         assertEquals(new Value(Instant.ofEpochSecond(0)), res.getValue("Instant"));
         assertEquals(new HashMap<>(), res.getValue("Map").asStructure().asMap());
         assertEquals(new Value(immutableContext), res.getValue("ImmutableContext"));
-        assertNull(res.getValue("nullKey"));
+        assertEquals(new Value(), res.getValue("nullKey"));
+    }
+
+    @Test
+    void asObjectHandlesNullValue() {
+        Map<String, Value> map = new HashMap<>();
+        map.put("null", new Value((String)null));
+        ImmutableStructure structure = new ImmutableStructure(map);
+        assertNull(structure.asObjectMap().get("null"));
+    }
+
+    @Test
+    void convertValueHandlesNullValue() {
+        ImmutableStructure structure = new ImmutableStructure();
+        assertNull(structure.convertValue(new Value((String)null)));
     }
 }
diff --git a/src/test/java/dev/openfeature/sdk/ValueTest.java b/src/test/java/dev/openfeature/sdk/ValueTest.java
index 53513af..816190a 100644
--- a/src/test/java/dev/openfeature/sdk/ValueTest.java
+++ b/src/test/java/dev/openfeature/sdk/ValueTest.java
@@ -1,5 +1,6 @@
 package dev.openfeature.sdk;
 
+import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -142,4 +143,9 @@ public class ValueTest {
 
         assertThrows(InstantiationException.class, ()-> new Value(list));
     }
+
+    @Test public void noOpFinalize() {
+        Value val = new Value();
+        assertDoesNotThrow(val::finalize); // does nothing, but we want to defined in and make it final.
+    }
 }