Repository: tefra/xsdata
Pull request #330 (2020-11-29 21:05:25)

JSON Bindings fixes

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo.png' alt='No Coverage information' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330) No Coverage information  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='0.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list)


codecov[bot]: # [Codecov](https://codecov.io/gh/tefra/xsdata/pull/330?src=pr&el=h1) Report
> Merging [#330](https://codecov.io/gh/tefra/xsdata/pull/330?src=pr&el=desc) (94b2e6d) into [master](https://codecov.io/gh/tefra/xsdata/commit/270ef2deceb7bccff7ad34817507d70efb864475?el=desc) (270ef2d) will **not change** coverage.
> The diff coverage is `100.00%`.

[![Impacted file tree graph](https://codecov.io/gh/tefra/xsdata/pull/330/graphs/tree.svg?width=650&height=150&src=pr&token=YzDDLtywvl)](https://codecov.io/gh/tefra/xsdata/pull/330?src=pr&el=tree)

```diff
@@            Coverage Diff            @@
##            master      #330   +/-   ##
=========================================
  Coverage   100.00%   100.00%           
=========================================
  Files           70        70           
  Lines         5630      5590   -40     
  Branches       975       975           
=========================================
- Hits          5630      5590   -40     
```


| [Impacted Files](https://codecov.io/gh/tefra/xsdata/pull/330?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [xsdata/formats/dataclass/filters.py](https://codecov.io/gh/tefra/xsdata/pull/330/diff?src=pr&el=tree#diff-eHNkYXRhL2Zvcm1hdHMvZGF0YWNsYXNzL2ZpbHRlcnMucHk=) | `100.00% <ø> (ø)` | |
| [xsdata/codegen/models.py](https://codecov.io/gh/tefra/xsdata/pull/330/diff?src=pr&el=tree#diff-eHNkYXRhL2NvZGVnZW4vbW9kZWxzLnB5) | `100.00% <100.00%> (ø)` | |
| [xsdata/formats/converter.py](https://codecov.io/gh/tefra/xsdata/pull/330/diff?src=pr&el=tree#diff-eHNkYXRhL2Zvcm1hdHMvY29udmVydGVyLnB5) | `100.00% <100.00%> (ø)` | |
| [xsdata/formats/dataclass/parsers/utils.py](https://codecov.io/gh/tefra/xsdata/pull/330/diff?src=pr&el=tree#diff-eHNkYXRhL2Zvcm1hdHMvZGF0YWNsYXNzL3BhcnNlcnMvdXRpbHMucHk=) | `100.00% <100.00%> (ø)` | |
| [xsdata/formats/dataclass/serializers/mixins.py](https://codecov.io/gh/tefra/xsdata/pull/330/diff?src=pr&el=tree#diff-eHNkYXRhL2Zvcm1hdHMvZGF0YWNsYXNzL3NlcmlhbGl6ZXJzL21peGlucy5weQ==) | `100.00% <100.00%> (ø)` | |
| [xsdata/cli.py](https://codecov.io/gh/tefra/xsdata/pull/330/diff?src=pr&el=tree#diff-eHNkYXRhL2NsaS5weQ==) | `100.00% <0.00%> (ø)` | |
| [xsdata/models/xsd.py](https://codecov.io/gh/tefra/xsdata/pull/330/diff?src=pr&el=tree#diff-eHNkYXRhL21vZGVscy94c2QucHk=) | `100.00% <0.00%> (ø)` | |
| [xsdata/models/wsdl.py](https://codecov.io/gh/tefra/xsdata/pull/330/diff?src=pr&el=tree#diff-eHNkYXRhL21vZGVscy93c2RsLnB5) | `100.00% <0.00%> (ø)` | |
| [xsdata/models/config.py](https://codecov.io/gh/tefra/xsdata/pull/330/diff?src=pr&el=tree#diff-eHNkYXRhL21vZGVscy9jb25maWcucHk=) | `100.00% <0.00%> (ø)` | |
| [xsdata/models/mixins.py](https://codecov.io/gh/tefra/xsdata/pull/330/diff?src=pr&el=tree#diff-eHNkYXRhL21vZGVscy9taXhpbnMucHk=) | `100.00% <0.00%> (ø)` | |
| ... and [18 more](https://codecov.io/gh/tefra/xsdata/pull/330/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/tefra/xsdata/pull/330?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/tefra/xsdata/pull/330?src=pr&el=footer). Last update [270ef2d...94b2e6d](https://codecov.io/gh/tefra/xsdata/pull/330?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo.png' alt='No Coverage information' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330) No Coverage information  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='0.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo.png' alt='No Coverage information' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330) No Coverage information  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='0.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo.png' alt='No Coverage information' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330) No Coverage information  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='0.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo.png' alt='No Coverage information' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330) No Coverage information  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='0.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list)


sonarcloud[bot]: Kudos, SonarCloud Quality Gate passed!

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/bug.png' alt='Bug' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG) [0 Bugs](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=BUG)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/vulnerability.png' alt='Vulnerability' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY) [0 Vulnerabilities](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=VULNERABILITY)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/security_hotspot.png' alt='Security Hotspot' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT) [0 Security Hotspots](https://sonarcloud.io/project/security_hotspots?id=tefra_xsdata&pullRequest=330&resolved=false&types=SECURITY_HOTSPOT)  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/common/code_smell.png' alt='Code Smell' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/RatingBadge/A.png' alt='A' width='16' height='16' />](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL) [0 Code Smells](https://sonarcloud.io/project/issues?id=tefra_xsdata&pullRequest=330&resolved=false&types=CODE_SMELL)

[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/CoverageChart/NoCoverageInfo.png' alt='No Coverage information' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330) No Coverage information  
[<img src='https://sonarsource.github.io/sonarcloud-github-static-resources/v2/checks/Duplications/3.png' alt='0.0%' width='16' height='16' />](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list) [0.0% Duplication](https://sonarcloud.io/component_measures?id=tefra_xsdata&pullRequest=330&metric=new_duplicated_lines_density&view=list)



Patch:
diff --git a/docs/examples/converter.py b/docs/examples/converter.py
index 1a7602c4..25d3b4c0 100644
--- a/docs/examples/converter.py
+++ b/docs/examples/converter.py
@@ -12,10 +12,10 @@ class Root:
 
 
 class DatetimeConverter(Converter):
-    def from_string(self, value: str, **kwargs: Any) -> datetime:
+    def deserialize(self, value: str, **kwargs: Any) -> datetime:
         return datetime.fromisoformat(value)
 
-    def to_string(self, value: datetime, **kwargs: Any) -> str:
+    def serialize(self, value: datetime, **kwargs: Any) -> str:
         return value.isoformat(sep=" ")
 
 
diff --git a/xsdata/codegen/models.py b/xsdata/codegen/models.py
index da4e846e..09137490 100644
--- a/xsdata/codegen/models.py
+++ b/xsdata/codegen/models.py
@@ -157,7 +157,7 @@ class Restrictions:
             elif key == "min_occurs" and value == 0:
                 continue
             elif key.endswith("clusive") and types:
-                value = converter.from_string(value, sorted_types)
+                value = converter.deserialize(value, sorted_types)
 
             result[key] = value
 
diff --git a/xsdata/formats/converter.py b/xsdata/formats/converter.py
index e222c88d..2c2d03bb 100644
--- a/xsdata/formats/converter.py
+++ b/xsdata/formats/converter.py
@@ -30,15 +30,15 @@ class Converter(metaclass=abc.ABCMeta):
     """Abstract converter class."""
 
     @abc.abstractmethod
-    def from_string(self, value: str, **kwargs: Any) -> Any:
+    def deserialize(self, value: Any, **kwargs: Any) -> Any:
         """
-        Convert from string.
+        Convert any type to the converter dedicated type.
 
         :raises ConverterError: if converter fails with and expected ValueError
         """
 
     @abc.abstractmethod
-    def to_string(self, value: Any, **kwargs: Any) -> str:
+    def serialize(self, value: Any, **kwargs: Any) -> str:
         """Convert to string."""
 
 
@@ -50,29 +50,25 @@ class ConverterAdapter:
 
     registry: Dict[Type, Converter] = field(default_factory=dict)
 
-    def from_string(self, value: Any, types: List[Type], **kwargs: Any) -> Any:
+    def deserialize(self, value: Any, types: List[Type], **kwargs: Any) -> Any:
         """
-        Attempt to convert a string to one of the given types.
+        Attempt to convert a any value to one of the given types.
 
-        If the input is not a string return the input value.
         If all attempts fail return the value input value and issue a warning.
 
         :return: The first successful converted value.
         """
-        if not isinstance(value, str):
-            return value
-
         for data_type in types:
             with contextlib.suppress(ConverterError):
                 instance = self.type_converter(data_type)
-                return instance.from_string(value, data_type=data_type, **kwargs)
+                return instance.deserialize(value, data_type=data_type, **kwargs)
 
         warnings.warn(
             f"Failed to convert value `{value}` to one of {types}", ConverterWarning
         )
         return value
 
-    def to_string(self, value: Any, **kwargs: Any) -> Any:
+    def serialize(self, value: Any, **kwargs: Any) -> Any:
         """
         Convert the given value to string, ignore None values.
 
@@ -82,10 +78,10 @@ class ConverterAdapter:
             return None
 
         if isinstance(value, list):
-            return " ".join([self.to_string(val, **kwargs) for val in value])
+            return " ".join([self.serialize(val, **kwargs) for val in value])
 
         instance = self.value_converter(value)
-        return instance.to_string(value, **kwargs)
+        return instance.serialize(value, **kwargs)
 
     def register_converter(self, data_type: Type, func: Union[Callable, Converter]):
         """
@@ -147,59 +143,63 @@ class ConverterAdapter:
 
 
 class BoolConverter(Converter):
-    def from_string(self, value: str, **kwargs: Any) -> bool:
-        val = value.strip()
+    def deserialize(self, value: Any, **kwargs: Any) -> bool:
+        if isinstance(value, str):
+
+            val = value.strip()
 
-        if val in ("true", "1"):
-            return True
+            if val in ("true", "1"):
+                return True
 
-        if val in ("false", "0"):
-            return False
+            if val in ("false", "0"):
+                return False
 
-        raise ConverterError(f"Invalid bool literal '{value}'")
+            raise ConverterError(f"Invalid bool literal '{value}'")
 
-    def to_string(self, value: bool, **kwargs: Any) -> str:
+        return True if value else False
+
+    def serialize(self, value: bool, **kwargs: Any) -> str:
         return "true" if value else "false"
 
 
 class IntConverter(Converter):
-    def from_string(self, value: str, **kwargs: Any) -> int:
+    def deserialize(self, value: Any, **kwargs: Any) -> int:
         try:
             return int(value)
-        except ValueError:
+        except (ValueError, TypeError):
             raise ConverterError()
 
-    def to_string(self, value: int, **kwargs: Any) -> str:
+    def serialize(self, value: int, **kwargs: Any) -> str:
         return str(value)
 
 
 class StrConverter(Converter):
-    def from_string(self, value: str, **kwargs: Any) -> str:
-        return value
+    def deserialize(self, value: Any, **kwargs: Any) -> str:
+        return str(value)
 
-    def to_string(self, value: str, **kwargs: Any) -> str:
-        return value
+    def serialize(self, value: str, **kwargs: Any) -> str:
+        return str(value)
 
 
 class FloatConverter(Converter):
-    def from_string(self, value: str, **kwargs: Any) -> float:
+    def deserialize(self, value: Any, **kwargs: Any) -> float:
         try:
             return float(value)
         except ValueError:
             raise ConverterError()
 
-    def to_string(self, value: float, **kwargs: Any) -> str:
+    def serialize(self, value: float, **kwargs: Any) -> str:
         return "NaN" if math.isnan(value) else str(value).upper()
 
 
 class DecimalConverter(Converter):
-    def from_string(self, value: str, **kwargs: Any) -> Decimal:
+    def deserialize(self, value: Any, **kwargs: Any) -> Decimal:
         try:
             return Decimal(value)
         except InvalidOperation:
             raise ConverterError()
 
-    def to_string(self, value: Decimal, **kwargs: Any) -> str:
+    def serialize(self, value: Decimal, **kwargs: Any) -> str:
         if value.is_infinite():
             return str(value).replace("Infinity", "INF")
 
@@ -207,7 +207,7 @@ class DecimalConverter(Converter):
 
 
 class QNameConverter(Converter):
-    def from_string(
+    def deserialize(
         self, value: str, ns_map: Optional[Dict] = None, **kwargs: Any
     ) -> QName:
         """
@@ -226,7 +226,7 @@ class QNameConverter(Converter):
 
         return QName(tag)
 
-    def to_string(
+    def serialize(
         self, value: QName, ns_map: Optional[Dict] = None, **kwargs: Any
     ) -> str:
         """
@@ -272,7 +272,7 @@ class QNameConverter(Converter):
 
 
 class LxmlQNameConverter(Converter):
-    def from_string(
+    def deserialize(
         self, value: str, ns_map: Optional[Dict] = None, **kwargs: Any
     ) -> etree.QName:
         """
@@ -290,7 +290,7 @@ class LxmlQNameConverter(Converter):
         except ValueError:
             raise ConverterError()
 
-    def to_string(
+    def serialize(
         self, value: etree.QName, ns_map: Optional[Dict] = None, **kwargs: Any
     ) -> str:
         """
@@ -311,8 +311,8 @@ class LxmlQNameConverter(Converter):
 
 
 class EnumConverter(Converter):
-    def from_string(
-        self, value: str, data_type: Optional[Type[Enum]] = None, **kwargs: Any
+    def deserialize(
+        self, value: Any, data_type: Optional[Type[Enum]] = None, **kwargs: Any
     ) -> Enum:
         if data_type is None or not issubclass(data_type, Enum):
             raise ConverterError("Provide a target data type enum class.")
@@ -325,7 +325,7 @@ class EnumConverter(Converter):
         # Suppress warnings
         with warnings.catch_warnings():
             warnings.simplefilter("ignore")
-            real_value = converter.from_string(value, [value_type], **kwargs)
+            real_value = converter.deserialize(value, [value_type], **kwargs)
 
         # Raise exception if the real value doesn't match the expected type.
         if not isinstance(real_value, value_type):
@@ -339,7 +339,7 @@ class EnumConverter(Converter):
             # Attempt #2 the enum might be derived from
             # xs:NMTOKENS or xs:list removing excess whitespace.
             if isinstance(real_value, str):
-                return data_type(" ".join(value.split()))
+                return data_type(" ".join(real_value.split()))
 
             # Attempt #3 some values are never equal try to match
             # canonical representations.
@@ -348,8 +348,8 @@ class EnumConverter(Converter):
         except (ValueError, StopIteration):
             raise ConverterError()
 
-    def to_string(self, value: Enum, **kwargs: Any) -> str:
-        return converter.to_string(value.value, **kwargs)
+    def serialize(self, value: Enum, **kwargs: Any) -> str:
+        return converter.serialize(value.value, **kwargs)
 
 
 @dataclass
@@ -360,13 +360,13 @@ class ProxyConverter(Converter):
 
     func: Callable
 
-    def from_string(self, value: str, **kwargs: Any) -> Any:
+    def deserialize(self, value: Any, **kwargs: Any) -> Any:
         try:
             return self.func(value)
         except ValueError:
             raise ConverterError
 
-    def to_string(self, value: Any, **kwargs: Any) -> str:
+    def serialize(self, value: Any, **kwargs: Any) -> str:
         return str(value)
 
 
diff --git a/xsdata/formats/dataclass/filters.py b/xsdata/formats/dataclass/filters.py
index 331e26f6..f4b4beb8 100644
--- a/xsdata/formats/dataclass/filters.py
+++ b/xsdata/formats/dataclass/filters.py
@@ -261,7 +261,7 @@ class Filters:
             return self.field_default_tokens(attr, types)
 
         return self.prepare_default_value(
-            converter.from_string(attr.default, types, ns_map=ns_map)
+            converter.deserialize(attr.default, types, ns_map=ns_map)
         )
 
     def field_default_enum(self, attr: Attr) -> str:
@@ -273,7 +273,7 @@ class Filters:
         assert isinstance(attr.default, str)
 
         tokens = ", ".join(
-            str(self.prepare_default_value(converter.from_string(val, types)))
+            str(self.prepare_default_value(converter.deserialize(val, types)))
             for val in attr.default.split()
         )
         return f"lambda: [{tokens}]"
diff --git a/xsdata/formats/dataclass/parsers/json.py b/xsdata/formats/dataclass/parsers/json.py
index 72e1ded3..a3b60665 100644
--- a/xsdata/formats/dataclass/parsers/json.py
+++ b/xsdata/formats/dataclass/parsers/json.py
@@ -1,6 +1,7 @@
 import io
 import json
 import pathlib
+import warnings
 from dataclasses import dataclass
 from dataclasses import field
 from dataclasses import fields
@@ -34,9 +35,29 @@ class JsonParser(AbstractParser):
     def parse(self, source: io.BytesIO, clazz: Type[T]) -> T:
         """Parse the JSON input stream and return the resulting object tree."""
         ctx = json.load(source)
-        return self.parse_context(ctx, clazz)
+        return self.bind_dataclass(ctx, clazz)
 
-    def parse_context(self, data: Dict, clazz: Type[T]) -> T:
+    def bind_value(self, var: XmlVar, value: Any) -> Any:
+        """Bind value according to the class var."""
+
+        if var.is_attributes:
+            return dict(value)
+
+        if var.is_clazz_union:
+            return self.bind_dataclass_union(value, var)
+
+        if var.clazz:
+            return self.bind_dataclass(value, var.clazz)
+
+        if var.is_wildcard:
+            return self.bind_wildcard(value)
+
+        if var.is_elements:
+            return self.bind_choice(value, var)
+
+        return ParserUtils.parse_value(value, var.types, var.default, tokens=var.tokens)
+
+    def bind_dataclass(self, data: Dict, clazz: Type[T]) -> T:
         """
         Recursively build the given model from the input dict data.
 
@@ -44,76 +65,80 @@ class JsonParser(AbstractParser):
         """
         params = {}
         for var in self.context.build(clazz).vars:
-            if not var.init:
-                continue
-
             value = self.get_value(data, var)
 
-            if value is None:
+            if value is None or not var.init:
                 continue
-            elif var.is_list:
+
+            if var.is_list:
                 params[var.name] = [self.bind_value(var, val) for val in value]
             else:
                 params[var.name] = self.bind_value(var, value)
 
         return clazz(**params)  # type: ignore
 
-    def bind_value(self, var: XmlVar, value: Any) -> Any:
-        """
-        Bind value according to the class var.
-
-        The return value can be:
-        - a dataclass instance
-        - a dictionary with unknown attributes
-        - a list of unknown elements
-        - an enumeration
-        - a primitive value
-        """
-        if var.dataclass and var.clazz:
-            return self.parse_context(value, var.clazz)
-
-        if var.is_attributes:
-            return dict(value)
+    def bind_dataclass_union(self, value: Dict, var: XmlVar) -> Any:
+        obj = None
+        max_score = -1.0
+        for clazz in var.types:
+            candidate = self.bind_dataclass(value, clazz)
+            score = ParserUtils.score_object(candidate)
+            if score > max_score:
+                max_score = score
+                obj = candidate
 
-        if var.is_wildcard:
-            return self.bind_wildcard(value)
-
-        if var.is_elements:
-            return self.bind_choice(value, var)
-
-        return ParserUtils.parse_value(value, var.types, var.default, tokens=var.tokens)
+        return obj
 
     def bind_wildcard(self, value: Any) -> Any:
         return (
-            value if isinstance(value, str) else self.parse_context(value, AnyElement)
+            value if isinstance(value, str) else self.bind_dataclass(value, AnyElement)
         )
 
     def bind_choice(self, value: Any, var: XmlVar) -> Any:
         if not isinstance(value, dict):
-            return value
+            return self.bind_choice_simple(value, var)
 
         if "qname" in value:
-            qname = value["qname"]
-            choice = var.find_choice(qname)
+            return self.bind_choice_generic(value, var)
 
-            if not choice:
-                raise ParserError(
-                    f"XmlElements undefined choice: `{var.name}` for qname `{qname}`"
-                )
+        return self.bind_choice_dataclass(value, var)
 
-            if "value" in value:
-                return DerivedElement(qname, self.bind_value(choice, value["value"]))
+    def bind_choice_simple(self, value: Any, var: XmlVar) -> Any:
+        orig_type = type(value)
+        for choice in var.choices:
+            if choice.dataclass:
+                continue
+
+            with warnings.catch_warnings():
+                warnings.simplefilter("ignore")
+
+                result = self.bind_value(choice, value)
+                if not isinstance(result, orig_type):
+                    return result
+
+        return value
 
-            return self.parse_context(value, AnyElement)
+    def bind_choice_generic(self, value: Dict, var: XmlVar) -> Any:
+        qname = value["qname"]
+        choice = var.find_choice(qname)
 
+        if not choice:
+            raise ParserError(
+                f"XmlElements undefined choice: `{var.name}` for qname `{qname}`"
+            )
+
+        if "value" in value:
+            return DerivedElement(qname, self.bind_value(choice, value["value"]))
+
+        return self.bind_dataclass(value, AnyElement)
+
+    def bind_choice_dataclass(self, value: Dict, var: XmlVar) -> Any:
         keys = set(value.keys())
         for choice in var.choices:
-            if not choice.dataclass:
-                continue
-
-            attrs = {f.name for f in fields(choice.clazz)}
-            if attrs == keys:
-                return self.bind_value(choice, value)
+            if choice.clazz:
+                attrs = {f.name for f in fields(choice.clazz)}
+                if attrs == keys:
+                    return self.bind_value(choice, value)
 
         raise ParserError(f"XmlElements undefined choice: `{var.name}` for `{value}`")
 
@@ -139,4 +164,4 @@ class JsonParser(AbstractParser):
 @dataclass
 class DictConverter(JsonParser):
     def convert(self, data: Dict, clazz: Type[T]) -> T:
-        return self.parse_context(data, clazz)
+        return self.bind_dataclass(data, clazz)
diff --git a/xsdata/formats/dataclass/parsers/nodes.py b/xsdata/formats/dataclass/parsers/nodes.py
index cf059f23..67b130e6 100644
--- a/xsdata/formats/dataclass/parsers/nodes.py
+++ b/xsdata/formats/dataclass/parsers/nodes.py
@@ -1,7 +1,6 @@
 import copy
 from dataclasses import dataclass
 from dataclasses import field
-from dataclasses import fields
 from typing import Any
 from typing import ClassVar
 from typing import Dict
@@ -349,7 +348,7 @@ class UnionNode(XmlNode):
         max_score = -1.0
         for clazz in self.var.types:
             candidate = self.parse_class(clazz)
-            score = self.score_object(candidate)
+            score = ParserUtils.score_object(candidate)
             if score > max_score:
                 max_score = score
                 obj = candidate
@@ -369,30 +368,6 @@ class UnionNode(XmlNode):
         except Exception:
             return None
 
-    @classmethod
-    def score_object(cls, obj: Any) -> float:
-        """
-        Score a dataclass instance by the field values types.
-
-        Weights:
-            1. None: 0
-            2. str: 1
-            3. *: 1.5
-        """
-
-        if not obj:
-            return -1.0
-
-        score = 0.0
-        for var in fields(obj):
-            val = getattr(obj, var.name)
-            if isinstance(val, str):
-                score += 1.0
-            elif val is not None:
-                score += 1.5
-
-        return score
-
 
 @dataclass
 class PrimitiveNode(XmlNode):
diff --git a/xsdata/formats/dataclass/parsers/utils.py b/xsdata/formats/dataclass/parsers/utils.py
index d7858e34..d25a99bf 100644
--- a/xsdata/formats/dataclass/parsers/utils.py
+++ b/xsdata/formats/dataclass/parsers/utils.py
@@ -1,3 +1,4 @@
+from dataclasses import fields
 from dataclasses import is_dataclass
 from typing import Any
 from typing import Dict
@@ -62,9 +63,9 @@ class ParserUtils:
 
         if tokens:
             value = value if isinstance(value, list) else value.split()
-            return [converter.from_string(val, types, ns_map=ns_map) for val in value]
+            return [converter.deserialize(val, types, ns_map=ns_map) for val in value]
 
-        return converter.from_string(value, types, ns_map=ns_map)
+        return converter.deserialize(value, types, ns_map=ns_map)
 
     @classmethod
     def bind_objects(cls, params: Dict, meta: XmlMeta, position: int, objects: List):
@@ -248,7 +249,7 @@ class ParserUtils:
         """Prepare parsed value before binding to a wildcard field."""
 
         if not is_dataclass(value):
-            value = AnyElement(qname=qname, text=value)
+            value = AnyElement(qname=qname, text=converter.serialize(value))
         elif not isinstance(value, (AnyElement, DerivedElement)):
             value = DerivedElement(qname=qname, value=value)
 
@@ -292,3 +293,27 @@ class ParserUtils:
             _, value = objects.pop(position)
             children.append(value)
         return children
+
+    @classmethod
+    def score_object(cls, obj: Any) -> float:
+        """
+        Score a dataclass instance by the field values types.
+
+        Weights:
+            1. None: 0
+            2. str: 1
+            3. *: 1.5
+        """
+
+        if not obj:
+            return -1.0
+
+        score = 0.0
+        for var in fields(obj):
+            val = getattr(obj, var.name)
+            if isinstance(val, str):
+                score += 1.0
+            elif val is not None:
+                score += 1.5
+
+        return score
diff --git a/xsdata/formats/dataclass/serializers/mixins.py b/xsdata/formats/dataclass/serializers/mixins.py
index 50cc7fe6..d6c862e3 100644
--- a/xsdata/formats/dataclass/serializers/mixins.py
+++ b/xsdata/formats/dataclass/serializers/mixins.py
@@ -124,7 +124,7 @@ class XmlWriter:
             value = QName(value)
 
         name = split_qname(key)
-        value = converter.to_string(value, ns_map=self.ns_map)
+        value = converter.serialize(value, ns_map=self.ns_map)
         self.attrs[name] = value
 
     def add_namespace(self, uri: Optional[str]):
@@ -148,7 +148,7 @@ class XmlWriter:
         current data as element tail content and queue it to be generated when the
         tag ends.
         """
-        value = converter.to_string(data, ns_map=self.ns_map)
+        value = converter.serialize(data, ns_map=self.ns_map)
         self.flush_start(is_nil=value is None or value == "")
 
         if value:


Test patch:
diff --git a/tests/formats/dataclass/parsers/test_json.py b/tests/formats/dataclass/parsers/test_json.py
index 50e95d5a..31533bcb 100644
--- a/tests/formats/dataclass/parsers/test_json.py
+++ b/tests/formats/dataclass/parsers/test_json.py
@@ -5,6 +5,7 @@ from tests import fixtures_dir
 from tests.fixtures.books import BookForm
 from tests.fixtures.books import Books
 from xsdata.exceptions import ParserError
+from xsdata.formats.dataclass.models.elements import XmlAttributes
 from xsdata.formats.dataclass.models.elements import XmlElement
 from xsdata.formats.dataclass.models.elements import XmlElements
 from xsdata.formats.dataclass.models.elements import XmlText
@@ -14,10 +15,14 @@ from xsdata.formats.dataclass.parsers.json import JsonParser
 
 
 class JsonParserTests(TestCase):
+    def setUp(self) -> None:
+        super().setUp()
+
+        self.parser = JsonParser()
+
     def test_parser(self):
         path = fixtures_dir.joinpath("books/books.json")
-        parser = JsonParser()
-        books = parser.from_path(path, Books)
+        books = self.parser.from_path(path, Books)
 
         self.assertIsInstance(books, Books)
 
@@ -47,22 +52,38 @@ class JsonParserTests(TestCase):
             books.book[1],
         )
 
-    def test_get_value(self):
-        data = dict(foo="bar", bar="foo")
+    def test_bind_value_with_attributes_var(self):
+        var = XmlAttributes(name="a", qname="a")
+        value = {"a": 1}
+        actual = self.parser.bind_value(var, value)
+        self.assertEqual(value, actual)
+        self.assertIsNot(value, actual)
 
-        foo_field = XmlText(name="foo", qname="foo", types=[str])
-        bar_field = XmlElement(name="bar", qname="bar", types=[str], list_element=True)
+    def test_bind_dataclass_union(self):
+        a = make_dataclass("a", [("x", int), ("y", str)])
+        b = make_dataclass("b", [("x", int), ("y", str), ("z", float)])
+        c = make_dataclass("c", [("x", int)])
+        var = XmlElement(name="union", qname="union", types=[a, b, c], dataclass=True)
 
-        self.assertEqual("bar", JsonParser.get_value(data, foo_field))
-        self.assertEqual(["foo"], JsonParser.get_value(data, bar_field))
-        self.assertIsNone(JsonParser.get_value({}, bar_field))
+        data = {"x": 1, "y": "foo", "z": 1.0}
+        actual = self.parser.bind_value(var, data)
 
-    def test_bind_choice_with_raw_primitive_value(self):
-        var = XmlElements(qname="compound", name="compound")
-        parser = JsonParser()
-        self.assertEqual(1, parser.bind_choice(1, var))
+        self.assertIsInstance(actual, b)
 
-    def test_bind_choice_with_raw_dict(self):
+    def test_bind_choice_simple(self):
+        var = XmlElements(
+            qname="compound",
+            name="compound",
+            choices=[
+                XmlElement(qname="int", name="int", types=[int]),
+                XmlElement(qname="generic", name="generic", dataclass=True),
+                XmlElement(qname="float", name="float", types=[float]),
+            ],
+        )
+        self.assertEqual(1.0, self.parser.bind_choice("1.0", var))
+        self.assertEqual("a", self.parser.bind_choice("a", var))
+
+    def test_bind_choice_dataclass(self):
         a = make_dataclass("a", [("x", int)])
         b = make_dataclass("b", [("x", int), ("y", str)])
 
@@ -76,19 +97,18 @@ class JsonParserTests(TestCase):
             ],
         )
 
-        parser = JsonParser()
-        self.assertEqual(a(1), parser.bind_choice({"x": 1}, var))
-        self.assertEqual(b(1, "2"), parser.bind_choice({"x": 1, "y": "2"}, var))
+        self.assertEqual(a(1), self.parser.bind_choice({"x": 1}, var))
+        self.assertEqual(b(1, "2"), self.parser.bind_choice({"x": 1, "y": "2"}, var))
 
         with self.assertRaises(ParserError) as cm:
-            parser.bind_choice({"x": 1, "y": "2", "z": 3}, var)
+            self.parser.bind_choice({"x": 1, "y": "2", "z": 3}, var)
 
         self.assertEqual(
             "XmlElements undefined choice: `compound` for `{'x': 1, 'y': '2', 'z': 3}`",
             str(cm.exception),
         )
 
-    def test_bind_choice_with_derived_value(self):
+    def test_bind_choice_generic_with_derived(self):
         var = XmlElements(
             qname="compound",
             name="compound",
@@ -98,13 +118,12 @@ class JsonParserTests(TestCase):
             ],
         )
 
-        parser = JsonParser()
         self.assertEqual(
             DerivedElement(qname="a", value=1),
-            parser.bind_choice({"qname": "a", "value": 1}, var),
+            self.parser.bind_choice({"qname": "a", "value": 1}, var),
         )
 
-    def test_bind_choice_with_generic_value(self):
+    def test_bind_choice_generic_with_wildcard(self):
         var = XmlElements(
             qname="compound",
             name="compound",
@@ -114,20 +133,28 @@ class JsonParserTests(TestCase):
             ],
         )
 
-        parser = JsonParser()
         self.assertEqual(
-            AnyElement(qname="a", text=1),
-            parser.bind_choice({"qname": "a", "text": 1}, var),
+            AnyElement(qname="a", text="1"),
+            self.parser.bind_choice({"qname": "a", "text": 1}, var),
         )
 
-    def test_bind_choice_with_unknown_qname(self):
+    def test_bind_choice_generic_with_unknown_qname(self):
         var = XmlElements(qname="compound", name="compound")
 
-        parser = JsonParser()
         with self.assertRaises(ParserError) as cm:
-            parser.bind_choice({"qname": "foo", "text": 1}, var)
+            self.parser.bind_choice({"qname": "foo", "text": 1}, var)
 
         self.assertEqual(
             "XmlElements undefined choice: `compound` for qname `foo`",
             str(cm.exception),
         )
+
+    def test_get_value(self):
+        data = dict(foo="bar", bar="foo")
+
+        foo_field = XmlText(name="foo", qname="foo", types=[str])
+        bar_field = XmlElement(name="bar", qname="bar", types=[str], list_element=True)
+
+        self.assertEqual("bar", self.parser.get_value(data, foo_field))
+        self.assertEqual(["foo"], self.parser.get_value(data, bar_field))
+        self.assertIsNone(self.parser.get_value({}, bar_field))
diff --git a/tests/formats/dataclass/parsers/test_nodes.py b/tests/formats/dataclass/parsers/test_nodes.py
index f72fe3ba..d44ba6d7 100644
--- a/tests/formats/dataclass/parsers/test_nodes.py
+++ b/tests/formats/dataclass/parsers/test_nodes.py
@@ -607,12 +607,6 @@ class UnionNodeTests(TestCase):
 
         self.assertEqual("Failed to parse union node: item", str(cm.exception))
 
-    def test_score_object(self):
-        self.assertEqual(-1.0, UnionNode.score_object(None))
-
-        cls = make_dataclass("b", [("x", int), ("y", str), ("z", Any)])
-        self.assertEqual(2.5, UnionNode.score_object(cls(1, "1", None)))
-
 
 class PrimitiveNodeTests(TestCase):
     @mock.patch.object(ParserUtils, "parse_value")
diff --git a/tests/formats/dataclass/parsers/test_utils.py b/tests/formats/dataclass/parsers/test_utils.py
index eb77f912..d3158a40 100644
--- a/tests/formats/dataclass/parsers/test_utils.py
+++ b/tests/formats/dataclass/parsers/test_utils.py
@@ -2,6 +2,7 @@ from dataclasses import dataclass
 from dataclasses import field
 from dataclasses import make_dataclass
 from dataclasses import replace
+from typing import Any
 from unittest import mock
 from unittest.case import TestCase
 
@@ -50,13 +51,13 @@ class ParserUtilsTests(TestCase):
         attrs = {QNames.XSI_TYPE: "xs:float"}
         self.assertEqual(DataType.FLOAT, ParserUtils.data_type(attrs, ns_map))
 
-    @mock.patch.object(ConverterAdapter, "from_string", return_value=2)
-    def test_parse_value(self, mock_from_string):
+    @mock.patch.object(ConverterAdapter, "deserialize", return_value=2)
+    def test_parse_value(self, mock_deserialize):
         self.assertEqual(1, ParserUtils.parse_value(None, [int], 1))
         self.assertIsNone(ParserUtils.parse_value(None, [int], lambda: 1))
 
         self.assertTrue(2, ParserUtils.parse_value("1", [int], None))
-        mock_from_string.assert_called_once_with("1", [int], ns_map=None)
+        mock_deserialize.assert_called_once_with("1", [int], ns_map=None)
 
     def test_parse_value_with_tokens_true(self):
         actual = ParserUtils.parse_value(" 1 2 3", [int], list, None, True)
@@ -65,7 +66,7 @@ class ParserUtilsTests(TestCase):
         actual = ParserUtils.parse_value(["1", "2", "3"], [int], list, None, True)
         self.assertEqual([1, 2, 3], actual)
 
-    @mock.patch.object(ConverterAdapter, "from_string", return_value=2)
+    @mock.patch.object(ConverterAdapter, "deserialize", return_value=2)
     def test_parse_value_with_ns_map(self, mock_to_python):
         ns_map = dict(a=1)
         ParserUtils.parse_value(" 1 2 3", [int], list, ns_map, True)
@@ -341,18 +342,24 @@ class ParserUtilsTests(TestCase):
         self.assertEqual(dict(a=["first", "txt", "tail", "tail"]), params)
 
     def test_prepare_generic_value(self):
-        @dataclass
-        class Fixture:
-            content: str
+        actual = ParserUtils.prepare_generic_value("a", 1)
+        expected = AnyElement(qname="a", text="1")
+        self.assertEqual(expected, actual)
 
         actual = ParserUtils.prepare_generic_value("a", "foo")
         expected = AnyElement(qname="a", text="foo")
         self.assertEqual(expected, actual)
 
-        fixture = Fixture("foo")
-        actual = ParserUtils.prepare_generic_value("a", fixture)
-        expected = DerivedElement(qname="a", value=fixture)
+        fixture = make_dataclass("Fixture", [("content", str)])
+        actual = ParserUtils.prepare_generic_value("a", fixture("foo"))
+        expected = DerivedElement(qname="a", value=fixture("foo"))
         self.assertEqual(expected, actual)
 
         actual = ParserUtils.prepare_generic_value("a", expected)
         self.assertIs(expected, actual)
+
+    def test_score_object(self):
+        self.assertEqual(-1.0, ParserUtils.score_object(None))
+
+        cls = make_dataclass("b", [("x", int), ("y", str), ("z", Any)])
+        self.assertEqual(2.5, ParserUtils.score_object(cls(1, "1", None)))
diff --git a/tests/formats/test_converter.py b/tests/formats/test_converter.py
index cfc8fc11..7b8d2321 100644
--- a/tests/formats/test_converter.py
+++ b/tests/formats/test_converter.py
@@ -23,51 +23,53 @@ from xsdata.models.enums import UseType
 
 
 class ConverterAdapterTests(TestCase):
-    def test_from_string(self):
+    def test_deserialize(self):
         with warnings.catch_warnings(record=True) as w:
-            self.assertEqual("a", converter.from_string("a", [int]))
+            self.assertEqual("a", converter.deserialize("a", [int]))
 
         self.assertEqual(
             "Failed to convert value `a` to one of [<class 'int'>]", str(w[-1].message)
         )
 
-        self.assertFalse(converter.from_string("false", [int, bool]))
-        self.assertEqual(1, converter.from_string("1", [int, bool]))
-
-    def test_to_string(self):
-        self.assertEqual(None, converter.from_string(None, [int]))
-        self.assertEqual("1", converter.to_string(1))
-        self.assertEqual("1 2 3", converter.to_string([1, "2", 3]))
-        self.assertEqual(None, converter.to_string(None))
-        self.assertEqual("1", converter.to_string(1))
-        self.assertEqual("1.5", converter.to_string(1.5))
-        self.assertEqual("true", converter.to_string(True))
-        self.assertEqual("optional", converter.to_string(UseType.OPTIONAL))
-        self.assertEqual("8.77683E-8", converter.to_string(Decimal("8.77683E-8")))
-        self.assertEqual("8.77683E-08", converter.to_string(float("8.77683E-8")))
+        self.assertFalse(converter.deserialize("false", [int, bool]))
+        self.assertEqual(1, converter.deserialize("1", [int, bool]))
+
+    def test_serialize(self):
+        with warnings.catch_warnings(record=True):
+            self.assertEqual(None, converter.deserialize(None, [int]))
+
+        self.assertEqual("1", converter.serialize(1))
+        self.assertEqual("1 2 3", converter.serialize([1, "2", 3]))
+        self.assertEqual(None, converter.serialize(None))
+        self.assertEqual("1", converter.serialize(1))
+        self.assertEqual("1.5", converter.serialize(1.5))
+        self.assertEqual("true", converter.serialize(True))
+        self.assertEqual("optional", converter.serialize(UseType.OPTIONAL))
+        self.assertEqual("8.77683E-8", converter.serialize(Decimal("8.77683E-8")))
+        self.assertEqual("8.77683E-08", converter.serialize(float("8.77683E-8")))
 
     def test_register_converter(self):
         class MinusOneInt(int):
             pass
 
         class MinusOneIntConverter(Converter):
-            def from_string(self, value: str, **kwargs: Any) -> Any:
+            def deserialize(self, value: str, **kwargs: Any) -> Any:
                 return int(value) - 1
 
-            def to_string(self, value: Any, **kwargs: Any) -> str:
+            def serialize(self, value: Any, **kwargs: Any) -> str:
                 return str(value)
 
         with warnings.catch_warnings(record=True) as w:
-            self.assertEqual("1", converter.from_string("1", [MinusOneInt]))
+            self.assertEqual("1", converter.deserialize("1", [MinusOneInt]))
 
         self.assertEqual(
             f"No converter registered for `{MinusOneInt}`", str(w[-1].message)
         )
 
         converter.register_converter(MinusOneInt, MinusOneIntConverter())
-        self.assertEqual(1, converter.from_string("2", [MinusOneInt]))
-        self.assertEqual(2, converter.from_string("3", [MinusOneInt]))
-        self.assertEqual("3", converter.to_string(MinusOneInt("3")))
+        self.assertEqual(1, converter.deserialize("2", [MinusOneInt]))
+        self.assertEqual(2, converter.deserialize("3", [MinusOneInt]))
+        self.assertEqual("3", converter.serialize(MinusOneInt("3")))
         converter.unregister_converter(MinusOneInt)
 
     def test_register_converter_with_lambda(self):
@@ -75,8 +77,8 @@ class ConverterAdapterTests(TestCase):
             pass
 
         converter.register_converter(MinusOneInt, lambda x: int(x) - 1)
-        self.assertEqual(1, converter.from_string("2", [MinusOneInt]))
-        self.assertEqual(2, converter.from_string("3", [MinusOneInt]))
+        self.assertEqual(1, converter.deserialize("2", [MinusOneInt]))
+        self.assertEqual(2, converter.deserialize("3", [MinusOneInt]))
         converter.unregister_converter(MinusOneInt)
 
 
@@ -84,93 +86,97 @@ class StrConverterTests(TestCase):
     def setUp(self):
         self.converter = StrConverter()
 
-    def test_from_string(self):
-        value = "a"
-        self.assertIs(value, self.converter.from_string(value))
+    def test_deserialize(self):
+        self.assertEqual("a", self.converter.deserialize("a"))
+        self.assertEqual("1", self.converter.deserialize(1))
 
-    def test_to_string(self):
-        value = "a"
-        self.assertIs(value, self.converter.to_string(value))
+    def test_serialize(self):
+        self.assertEqual("a", self.converter.serialize("a"))
+        self.assertEqual("1", self.converter.serialize(1))
 
 
 class BoolConverterTests(TestCase):
     def setUp(self):
         self.converter = BoolConverter()
 
-    def test_from_string(self):
+    def test_deserialize(self):
         with self.assertRaises(ConverterError):
-            self.converter.from_string("True")
+            self.converter.deserialize("True")
 
-        self.assertTrue(self.converter.from_string("true"))
-        self.assertTrue(self.converter.from_string("1"))
-        self.assertFalse(self.converter.from_string("false"))
-        self.assertFalse(self.converter.from_string("0"))
+        self.assertTrue(self.converter.deserialize("true"))
+        self.assertTrue(self.converter.deserialize("1"))
+        self.assertFalse(self.converter.deserialize("false"))
+        self.assertFalse(self.converter.deserialize("0"))
+        self.assertTrue(self.converter.deserialize(True))
+        self.assertTrue(self.converter.deserialize(1))
+        self.assertFalse(self.converter.deserialize(False))
+        self.assertFalse(self.converter.deserialize(0))
 
-    def test_to_string(self):
-        self.assertEqual("true", self.converter.to_string(True))
-        self.assertEqual("false", self.converter.to_string(False))
+    def test_serialize(self):
+        self.assertEqual("true", self.converter.serialize(True))
+        self.assertEqual("false", self.converter.serialize(False))
 
 
 class IntConverterTests(TestCase):
     def setUp(self):
         self.converter = IntConverter()
 
-    def test_from_string(self):
+    def test_deserialize(self):
         with self.assertRaises(ConverterError):
-            self.converter.from_string("a")
+            self.converter.deserialize("a")
 
-        self.assertEqual(2, self.converter.from_string("2"))
-        self.assertEqual(2, self.converter.from_string("+2"))
-        self.assertEqual(-2, self.converter.from_string("-2"))
+        self.assertEqual(2, self.converter.deserialize("2"))
+        self.assertEqual(2, self.converter.deserialize("+2"))
+        self.assertEqual(-2, self.converter.deserialize("-2"))
 
-    def test_to_string(self):
-        self.assertEqual("2", self.converter.to_string(2))
+    def test_serialize(self):
+        self.assertEqual("2", self.converter.serialize(2))
 
 
 class FloatConverterTests(TestCase):
     def setUp(self):
         self.converter = FloatConverter()
 
-    def test_from_string(self):
+    def test_deserialize(self):
         with self.assertRaises(ConverterError):
-            self.converter.from_string("a")
+            self.converter.deserialize("a")
 
-        self.assertEqual(2.0, self.converter.from_string("2"))
-        self.assertEqual(2.1, self.converter.from_string("2.1"))
+        self.assertEqual(2.0, self.converter.deserialize("2"))
+        self.assertEqual(2.1, self.converter.deserialize("2.1"))
 
-    def test_to_string(self):
-        self.assertEqual("2.1", self.converter.to_string(2.1))
-        self.assertEqual("INF", self.converter.to_string(float("inf")))
-        self.assertEqual("INF", self.converter.to_string(float("+inf")))
-        self.assertEqual("-INF", self.converter.to_string(float("-inf")))
-        self.assertEqual("NaN", self.converter.to_string(float("nan")))
-        self.assertEqual("8.77683E-08", self.converter.to_string(float("8.77683E-8")))
+    def test_serialize(self):
+        self.assertEqual("2.1", self.converter.serialize(2.1))
+        self.assertEqual("INF", self.converter.serialize(float("inf")))
+        self.assertEqual("INF", self.converter.serialize(float("+inf")))
+        self.assertEqual("-INF", self.converter.serialize(float("-inf")))
+        self.assertEqual("NaN", self.converter.serialize(float("nan")))
+        self.assertEqual("8.77683E-08", self.converter.serialize(float("8.77683E-8")))
 
 
 class DecimalConverterTests(TestCase):
     def setUp(self):
         self.converter = DecimalConverter()
 
-    def test_from_string(self):
+    def test_deserialize(self):
         with self.assertRaises(ConverterError):
-            self.converter.from_string("a")
+            self.converter.deserialize("a")
 
-        self.assertEqual(Decimal(1), self.converter.from_string("1"))
+        self.assertEqual(Decimal(1), self.converter.deserialize("1"))
 
-    def test_to_string(self):
-        self.assertEqual("2.1", self.converter.to_string(Decimal("2.1")))
-        self.assertEqual("INF", self.converter.to_string(Decimal("inf")))
-        self.assertEqual("INF", self.converter.to_string(Decimal("+inf")))
-        self.assertEqual("-INF", self.converter.to_string(Decimal("-inf")))
-        self.assertEqual("8.77683E-8", self.converter.to_string(Decimal("8.77683E-8")))
+    def test_serialize(self):
+        self.assertEqual("2.1", self.converter.serialize(Decimal("2.1")))
+        self.assertEqual("INF", self.converter.serialize(Decimal("inf")))
+        self.assertEqual("INF", self.converter.serialize(Decimal("+inf")))
+        self.assertEqual("-INF", self.converter.serialize(Decimal("-inf")))
+        self.assertEqual("8.77683E-8", self.converter.serialize(Decimal("8.77683E-8")))
 
 
 class LxmlQNameConverterTests(TestCase):
     def setUp(self):
         self.converter = LxmlQNameConverter()
 
-    def test_from_string(self):
-        convert = self.converter.from_string
+    def test_deserialize(self):
+        convert = self.converter.deserialize
         with self.assertRaises(ConverterError):
             convert("a:b")
 
@@ -180,9 +186,9 @@ class LxmlQNameConverterTests(TestCase):
         self.assertEqual(etree.QName("a"), convert("a", ns_map={}))
         self.assertEqual(etree.QName("aa", "b"), convert("a:b", ns_map={"a": "aa"}))
 
-    def test_to_string(self):
+    def test_serialize(self):
         ns_map = {"c_prefix": "c"}
-        convert = self.converter.to_string
+        convert = self.converter.serialize
 
         self.assertEqual("a", convert(etree.QName("a"), ns_map=ns_map))
         self.assertEqual("a", convert(etree.QName("a")))
@@ -196,8 +202,8 @@ class QNameConverterTests(TestCase):
     def setUp(self):
         self.converter = QNameConverter()
 
-    def test_from_string(self):
-        convert = self.converter.from_string
+    def test_deserialize(self):
+        convert = self.converter.deserialize
         with self.assertRaises(ConverterError) as cm:
             convert("a:b")
 
@@ -217,9 +223,9 @@ class QNameConverterTests(TestCase):
         self.assertEqual(QName("aa", "b"), convert("a:b", ns_map={"a": "aa"}))
         self.assertEqual(QName("{a}b"), convert("{a}b"))
 
-    def test_to_string(self):
+    def test_serialize(self):
         ns_map = {"c_prefix": "c"}
-        convert = self.converter.to_string
+        convert = self.converter.serialize
 
         self.assertEqual("a", convert(QName("a"), ns_map=ns_map))
         self.assertEqual("a", convert(QName("a")))
@@ -233,11 +239,11 @@ class EnumConverterTests(TestCase):
     def setUp(self):
         self.converter = EnumConverter()
 
-    def test_from_string(self):
+    def test_deserialize(self):
         class Fixture(Enum):
             two_point_one = 2.1
 
-        convert = self.converter.from_string
+        convert = self.converter.deserialize
         with self.assertRaises(ConverterError):
             with warnings.catch_warnings(record=True) as w:
                 convert("a", data_type=Fixture)
@@ -246,50 +252,50 @@ class EnumConverterTests(TestCase):
 
         self.assertEqual(Fixture.two_point_one, convert("2.1", data_type=Fixture))
 
-    def test_from_string_with_list_derived_enum(self):
+    def test_deserialize_with_list_derived_enum(self):
         class Fixture(Enum):
             a = "a a a"
 
-        convert = self.converter.from_string
+        convert = self.converter.deserialize
         self.assertEqual(Fixture.a, convert(" a \na a  ", data_type=Fixture))
 
-    def test_from_string_with_value_never_equal_to_anything(self):
+    def test_deserialize_with_value_never_equal_to_anything(self):
         class Fixture(Enum):
             a = Decimal("NaN")
 
-        convert = self.converter.from_string
+        convert = self.converter.deserialize
         self.assertEqual(Fixture.a, convert("NaN", data_type=Fixture))
 
         with self.assertRaises(ConverterError):
             convert("1.0", data_type=Fixture)
 
-    def test_from_string_raises_exception_on_missing_data_type(self):
+    def test_deserialize_raises_exception_on_missing_data_type(self):
         with self.assertRaises(ConverterError) as cm:
-            self.converter.from_string("a")
+            self.converter.deserialize("a")
 
         self.assertEqual("Provide a target data type enum class.", str(cm.exception))
 
-    def test_to_string(self):
+    def test_serialize(self):
         class Fixture(Enum):
             a = QName("a", "b")
             b = Decimal("+inf")
             c = 2.1
 
         ns_map = {}
-        self.assertEqual("ns0:b", self.converter.to_string(Fixture.a, ns_map=ns_map))
-        self.assertEqual("INF", self.converter.to_string(Fixture.b))
-        self.assertEqual("2.1", self.converter.to_string(Fixture.c))
+        self.assertEqual("ns0:b", self.converter.serialize(Fixture.a, ns_map=ns_map))
+        self.assertEqual("INF", self.converter.serialize(Fixture.b))
+        self.assertEqual("2.1", self.converter.serialize(Fixture.c))
 
 
 class ProxyConverterTests(TestCase):
     def setUp(self):
         self.converter = ProxyConverter(lambda x: int(x))
 
-    def test_from_string(self):
+    def test_deserialize(self):
         with self.assertRaises(ConverterError):
-            self.converter.from_string("a")
+            self.converter.deserialize("a")
 
-        self.assertEqual(1, self.converter.from_string("1"))
+        self.assertEqual(1, self.converter.deserialize("1"))
 
-    def test_to_string(self):
-        self.assertEqual("1", self.converter.to_string(1))
+    def test_serialize(self):
+        self.assertEqual("1", self.converter.serialize(1))