Repository: JodaOrg/joda-beans
Branch: main
Commit: ada2a8fae2c5
Files: 427
Total size: 3.6 MB
Directory structure:
gitextract_08ef56yp/
├── .coderabbit.yaml
├── .github/
│ ├── FUNDING.yml
│ ├── SECURITY.md
│ ├── dependabot.yml
│ ├── maven-settings.xml
│ └── workflows/
│ ├── build.yml
│ ├── release.yml
│ └── website.yml
├── .gitignore
├── LICENSE.txt
├── NOTICE.txt
├── README.md
├── RELEASE-NOTES.txt
├── pom.xml
└── src/
├── changes/
│ └── changes.xml
├── main/
│ ├── assembly/
│ │ └── dist.xml
│ ├── checkstyle/
│ │ └── checkstyle.xml
│ ├── java/
│ │ ├── module-info.java
│ │ └── org/
│ │ └── joda/
│ │ └── beans/
│ │ ├── Bean.java
│ │ ├── BeanBuilder.java
│ │ ├── BeanIterator.java
│ │ ├── DynamicBean.java
│ │ ├── DynamicMetaBean.java
│ │ ├── ImmutableBean.java
│ │ ├── JodaBeanUtils.java
│ │ ├── MetaBean.java
│ │ ├── MetaBeanProvider.java
│ │ ├── MetaBeans.java
│ │ ├── MetaProperty.java
│ │ ├── MetaProvider.java
│ │ ├── Property.java
│ │ ├── PropertyPath.java
│ │ ├── PropertyStyle.java
│ │ ├── ResolvedType.java
│ │ ├── TypedMetaBean.java
│ │ ├── gen/
│ │ │ ├── BeanCodeGen.java
│ │ │ ├── BeanCodeGenException.java
│ │ │ ├── BeanData.java
│ │ │ ├── BeanDefinition.java
│ │ │ ├── BeanGen.java
│ │ │ ├── BeanGenConfig.java
│ │ │ ├── BeanParser.java
│ │ │ ├── BuilderGen.java
│ │ │ ├── CopyGen.java
│ │ │ ├── DerivedProperty.java
│ │ │ ├── GetterGen.java
│ │ │ ├── ImmutableConstructor.java
│ │ │ ├── ImmutableDefaults.java
│ │ │ ├── ImmutablePreBuild.java
│ │ │ ├── ImmutableValidator.java
│ │ │ ├── PropertyData.java
│ │ │ ├── PropertyDefinition.java
│ │ │ ├── PropertyGen.java
│ │ │ ├── PropertyParser.java
│ │ │ ├── SetterGen.java
│ │ │ └── package-info.java
│ │ ├── impl/
│ │ │ ├── BasicBean.java
│ │ │ ├── BasicBeanBuilder.java
│ │ │ ├── BasicImmutableBeanBuilder.java
│ │ │ ├── BasicMetaBean.java
│ │ │ ├── BasicMetaProperty.java
│ │ │ ├── BasicProperty.java
│ │ │ ├── BasicPropertyMap.java
│ │ │ ├── BufferingBeanBuilder.java
│ │ │ ├── RecordBean.java
│ │ │ ├── RecordBeanBuilder.java
│ │ │ ├── RecordMetaBean.java
│ │ │ ├── RecordMetaProperty.java
│ │ │ ├── StandaloneMetaProperty.java
│ │ │ ├── direct/
│ │ │ │ ├── DirectBean.java
│ │ │ │ ├── DirectBeanBuilder.java
│ │ │ │ ├── DirectFieldsBeanBuilder.java
│ │ │ │ ├── DirectMetaBean.java
│ │ │ │ ├── DirectMetaProperty.java
│ │ │ │ ├── DirectMetaPropertyMap.java
│ │ │ │ ├── DirectPrivateBeanBuilder.java
│ │ │ │ ├── MinimalMetaBean.java
│ │ │ │ ├── MinimalMetaProperty.java
│ │ │ │ └── package-info.java
│ │ │ ├── flexi/
│ │ │ │ ├── FlexiBean.java
│ │ │ │ ├── FlexiBeanBuilder.java
│ │ │ │ ├── FlexiMetaBean.java
│ │ │ │ ├── FlexiMetaProperty.java
│ │ │ │ └── package-info.java
│ │ │ ├── light/
│ │ │ │ ├── LightBeanBuilder.java
│ │ │ │ ├── LightMetaBean.java
│ │ │ │ ├── LightMetaProperty.java
│ │ │ │ ├── PropertyGetter.java
│ │ │ │ ├── PropertySetter.java
│ │ │ │ └── package-info.java
│ │ │ ├── map/
│ │ │ │ ├── MapBean.java
│ │ │ │ ├── MapBeanBuilder.java
│ │ │ │ ├── MapBeanMetaProperty.java
│ │ │ │ ├── MapMetaBean.java
│ │ │ │ └── package-info.java
│ │ │ ├── package-info.java
│ │ │ └── reflection/
│ │ │ ├── ReflectiveMetaBean.java
│ │ │ ├── ReflectiveMetaProperty.java
│ │ │ └── package-info.java
│ │ ├── package-info.java
│ │ ├── ser/
│ │ │ ├── CollectSerIteratorFactory.java
│ │ │ ├── DefaultDeserializer.java
│ │ │ ├── GuavaSerIteratorFactory.java
│ │ │ ├── JodaBeanMimeType.java
│ │ │ ├── JodaBeanSer.java
│ │ │ ├── JodaBeanSerFormat.java
│ │ │ ├── JodaBeanSmartReader.java
│ │ │ ├── LenientDeserializer.java
│ │ │ ├── LinkedByteArrayOutputStream.java
│ │ │ ├── SerCategory.java
│ │ │ ├── SerDeserializer.java
│ │ │ ├── SerDeserializerProvider.java
│ │ │ ├── SerDeserializers.java
│ │ │ ├── SerIterable.java
│ │ │ ├── SerIterator.java
│ │ │ ├── SerIteratorFactory.java
│ │ │ ├── SerOptional.java
│ │ │ ├── SerTypeMapper.java
│ │ │ ├── bin/
│ │ │ │ ├── AbstractBinReader.java
│ │ │ │ ├── AbstractBinWriter.java
│ │ │ │ ├── BeanPack.java
│ │ │ │ ├── BeanPackInput.java
│ │ │ │ ├── BeanPackOutput.java
│ │ │ │ ├── BeanPackVisualizer.java
│ │ │ │ ├── BeanReferences.java
│ │ │ │ ├── JodaBeanBinFormat.java
│ │ │ │ ├── JodaBeanBinReader.java
│ │ │ │ ├── JodaBeanBinWriter.java
│ │ │ │ ├── JodaBeanPackedBinReader.java
│ │ │ │ ├── JodaBeanPackedBinWriter.java
│ │ │ │ ├── JodaBeanReferencingBinReader.java
│ │ │ │ ├── JodaBeanReferencingBinWriter.java
│ │ │ │ ├── JodaBeanStandardBinReader.java
│ │ │ │ ├── JodaBeanStandardBinWriter.java
│ │ │ │ ├── MsgPack.java
│ │ │ │ ├── MsgPackInput.java
│ │ │ │ ├── MsgPackOutput.java
│ │ │ │ ├── MsgPackVisualizer.java
│ │ │ │ └── package-info.java
│ │ │ ├── json/
│ │ │ │ ├── AbstractJsonReader.java
│ │ │ │ ├── JodaBeanJsonNumberFormat.java
│ │ │ │ ├── JodaBeanJsonReader.java
│ │ │ │ ├── JodaBeanJsonWriter.java
│ │ │ │ ├── JodaBeanSimpleJsonReader.java
│ │ │ │ ├── JodaBeanSimpleJsonWriter.java
│ │ │ │ ├── JsonEvent.java
│ │ │ │ ├── JsonInput.java
│ │ │ │ ├── JsonOutput.java
│ │ │ │ └── package-info.java
│ │ │ ├── map/
│ │ │ │ ├── JodaBeanSimpleMapReader.java
│ │ │ │ ├── JodaBeanSimpleMapWriter.java
│ │ │ │ └── package-info.java
│ │ │ ├── package-info.java
│ │ │ └── xml/
│ │ │ ├── JodaBeanXml.java
│ │ │ ├── JodaBeanXmlReader.java
│ │ │ ├── JodaBeanXmlWriter.java
│ │ │ └── package-info.java
│ │ └── test/
│ │ ├── BeanAssert.java
│ │ ├── BeanComparisonError.java
│ │ ├── JodaBeanTests.java
│ │ └── package-info.java
│ └── resources/
│ └── org/
│ └── joda/
│ └── beans/
│ └── gen/
│ ├── guava.ini
│ └── jdk.ini
├── site/
│ ├── markdown/
│ │ ├── enterprise.md
│ │ ├── index.md
│ │ ├── licensecover.md
│ │ ├── migration.md
│ │ ├── related.md
│ │ ├── userguide-codegen.md
│ │ ├── userguide-serialization.md
│ │ └── userguide.md
│ ├── resources/
│ │ ├── css/
│ │ │ └── site.css
│ │ └── download.html
│ └── site.xml
└── test/
├── java/
│ └── org/
│ └── joda/
│ └── beans/
│ ├── Examples.java
│ ├── TestAddress.java
│ ├── TestArray.java
│ ├── TestBasicBean.java
│ ├── TestBeanCodeGenException.java
│ ├── TestBeanIterator.java
│ ├── TestClone.java
│ ├── TestCompanyAddress.java
│ ├── TestFinalFieldBean.java
│ ├── TestFlexiBean.java
│ ├── TestImmutable.java
│ ├── TestJodaBeanUtils.java
│ ├── TestLight.java
│ ├── TestMapBean.java
│ ├── TestMetaBean.java
│ ├── TestMetaBeanProvider.java
│ ├── TestMetaBeans.java
│ ├── TestMetaInvoke.java
│ ├── TestMinimal.java
│ ├── TestMutableDerived.java
│ ├── TestMutableListBeans.java
│ ├── TestOptionalBean.java
│ ├── TestPair.java
│ ├── TestPerson.java
│ ├── TestPropertyPath.java
│ ├── TestPropertyStyle.java
│ ├── TestRecordBean.java
│ ├── TestReflective.java
│ ├── TestResolvedType.java
│ ├── TestResult.java
│ ├── TestSubBean.java
│ ├── TestValidateBean.java
│ ├── sample/
│ │ ├── AbstractResult.java
│ │ ├── Address.java
│ │ ├── AddressResult.java
│ │ ├── ClassAnnotation.java
│ │ ├── ClonePerson.java
│ │ ├── Company.java
│ │ ├── CompanyAddress.java
│ │ ├── CompanyAddressMidResult.java
│ │ ├── CompanyAddressResult.java
│ │ ├── ComplexAnnotation.java
│ │ ├── Documentation.java
│ │ ├── DocumentationHolder.java
│ │ ├── DoubleGenericsComplexExtendsSuperTwoGenerics.java
│ │ ├── DoubleGenericsNoExtendsNoSuper.java
│ │ ├── DoubleGenericsSimpleSuper.java
│ │ ├── DoubleGenericsWithExtendsNoSuper.java
│ │ ├── DoubleGenericsWithExtendsSuperNoGenerics.java
│ │ ├── DoubleGenericsWithExtendsSuperOneGeneric.java
│ │ ├── DoubleGenericsWithExtendsSuperTwoGenerics.java
│ │ ├── FieldNamesImmutable.java
│ │ ├── FieldNamesImmutableMinimal.java
│ │ ├── FieldNamesLight.java
│ │ ├── FieldNamesMutable.java
│ │ ├── FieldNamesMutableMinimal.java
│ │ ├── FinalFieldBean.java
│ │ ├── GenericAllFinal.java
│ │ ├── GenericArray.java
│ │ ├── GenericInterfaceBase.java
│ │ ├── GenericInterfaceChild.java
│ │ ├── GenericInterfaceImpl.java
│ │ ├── GenericInterfaceMid.java
│ │ ├── GenericSubWrapper.java
│ │ ├── GenericUnionType.java
│ │ ├── GenericWrapperDocumentation.java
│ │ ├── IKey.java
│ │ ├── INamedKey.java
│ │ ├── IPerson.java
│ │ ├── ImmAddress.java
│ │ ├── ImmArrays.java
│ │ ├── ImmClone.java
│ │ ├── ImmComplexAnnotation.java
│ │ ├── ImmDefault.java
│ │ ├── ImmDeprecated.java
│ │ ├── ImmDocumentationHolder.java
│ │ ├── ImmDocumentationResult.java
│ │ ├── ImmDoubleArray.java
│ │ ├── ImmDoubleFloat.java
│ │ ├── ImmEmpty.java
│ │ ├── ImmFieldGetter.java
│ │ ├── ImmGeneric.java
│ │ ├── ImmGenericArray.java
│ │ ├── ImmGenericCollections.java
│ │ ├── ImmGenericLinkedRefs.java
│ │ ├── ImmGenericNonFinal.java
│ │ ├── ImmGuava.java
│ │ ├── ImmJodaConvertBean.java
│ │ ├── ImmJodaConvertWrapper.java
│ │ ├── ImmKey.java
│ │ ├── ImmKeyDeserializer.java
│ │ ├── ImmKeyHolder.java
│ │ ├── ImmKeyHolderDeserializer.java
│ │ ├── ImmKeyList.java
│ │ ├── ImmMappedKey.java
│ │ ├── ImmMinimalMetaBuilder.java
│ │ ├── ImmMinimalPrivateBuilder.java
│ │ ├── ImmNamedKey.java
│ │ ├── ImmOptional.java
│ │ ├── ImmOptionalMeta.java
│ │ ├── ImmPackageScoped.java
│ │ ├── ImmPair.java
│ │ ├── ImmPerson.java
│ │ ├── ImmPersonAbstract.java
│ │ ├── ImmPersonNonFinal.java
│ │ ├── ImmPrivateMeta.java
│ │ ├── ImmSubPersonFromAbstract.java
│ │ ├── ImmSubPersonNonFinal.java
│ │ ├── ImmSubSubPersonFinal.java
│ │ ├── ImmTolerance.java
│ │ ├── ImmTreeNode.java
│ │ ├── ImmTypes.java
│ │ ├── ImmUnusedGeneric.java
│ │ ├── JodaConvertBean.java
│ │ ├── JodaConvertInterface.java
│ │ ├── JodaConvertWrapper.java
│ │ ├── LightEmpty.java
│ │ ├── LightImmutable.java
│ │ ├── LightImmutableGeneric.java
│ │ ├── LightImmutableSimple.java
│ │ ├── LightMutable.java
│ │ ├── LightMutableGeneric.java
│ │ ├── LightMutableSimple.java
│ │ ├── MetaBeanLoad.java
│ │ ├── MidAbstractResult.java
│ │ ├── MinimalEmpty.java
│ │ ├── MinimalImmutable.java
│ │ ├── MinimalImmutableGeneric.java
│ │ ├── MinimalImmutableSimple.java
│ │ ├── MinimalManualBuilder.java
│ │ ├── MinimalMutable.java
│ │ ├── MinimalMutableGeneric.java
│ │ ├── MinimalMutableGenericSimple.java
│ │ ├── MinimalMutableSimple.java
│ │ ├── MutableBaseBean.java
│ │ ├── MutableDeprecated.java
│ │ ├── MutableDerived.java
│ │ ├── MutableDerivedBean.java
│ │ ├── MutableEmptyBase.java
│ │ ├── MutableListFinalBean.java
│ │ ├── MutableListNonFinalBean.java
│ │ ├── MutableOptional.java
│ │ ├── MutableTypes.java
│ │ ├── NoClone.java
│ │ ├── NoGenEquals.java
│ │ ├── NoGenToString.java
│ │ ├── NoProperties.java
│ │ ├── Pair.java
│ │ ├── PairBuilder.java
│ │ ├── PairDeserializer.java
│ │ ├── PairManualInnerBuilder.java
│ │ ├── PairManualTopLevelBuilder.java
│ │ ├── Person.java
│ │ ├── PersonDocumentation.java
│ │ ├── PrimitiveBean.java
│ │ ├── PropertyDefBean.java
│ │ ├── RWOnlyBean.java
│ │ ├── RecordStrIntPair.java
│ │ ├── ReflectiveMutable.java
│ │ ├── Risk.java
│ │ ├── RiskFactory.java
│ │ ├── RiskLevel.java
│ │ ├── RiskPerception.java
│ │ ├── SimpleAnnotation.java
│ │ ├── SimpleJson.java
│ │ ├── SimpleName.java
│ │ ├── SimplePerson.java
│ │ ├── SimplePersonWithBuilderFinal.java
│ │ ├── SimplePersonWithBuilderNonFinal.java
│ │ ├── SimpleSubPersonWithBuilderFinal.java
│ │ ├── SimpleSubPersonWithBuilderNonFinal.java
│ │ ├── SubDecimal.java
│ │ ├── SubPerson.java
│ │ ├── SubValidateBean.java
│ │ ├── SubWrapper.java
│ │ ├── TestRWOnlyBean.java
│ │ ├── TupleFinal.java
│ │ ├── TupleImmutable.java
│ │ ├── TupleNonFinal.java
│ │ ├── TupleSub.java
│ │ ├── TweakedPair.java
│ │ ├── UserAccount.java
│ │ ├── ValidateBean.java
│ │ ├── ValidateBeanCheck.java
│ │ ├── WeirdFormat.java
│ │ ├── Wrapper.java
│ │ └── WrapperToDoubleGenerics.java
│ ├── ser/
│ │ ├── AtomicReference.java
│ │ ├── BigDecimal.java
│ │ ├── Normal.java
│ │ ├── SerTestHelper.java
│ │ ├── TestJodaBeanBinFormat.java
│ │ ├── TestLinkedByteArrayOutputStream.java
│ │ ├── TestSerDeserializerProvider.java
│ │ ├── TestSerTypeMapper.java
│ │ ├── TestSerializeSmartReader.java
│ │ ├── bin/
│ │ │ ├── TestBinPerformance.java
│ │ │ ├── TestSerializePackedBin.java
│ │ │ ├── TestSerializeReferencingBin.java
│ │ │ └── TestSerializeStandardBin.java
│ │ ├── json/
│ │ │ ├── TestJsonInput.java
│ │ │ ├── TestJsonOutput.java
│ │ │ ├── TestJsonPerformance.java
│ │ │ ├── TestSerializeJson.java
│ │ │ └── TestSerializeJsonSimple.java
│ │ ├── lowerCase.java
│ │ ├── map/
│ │ │ └── TestSerializeSimpleMap.java
│ │ └── xml/
│ │ ├── MockRenameDeserializer.java
│ │ ├── MockSemanticChangeDeserializer.java
│ │ ├── MockTypeChangeDeserializer.java
│ │ ├── TestDeserializeXml.java
│ │ └── TestSerializeXml.java
│ └── test/
│ ├── TestBeanAssert.java
│ └── TestCoverage.java
└── resources/
├── META-INF/
│ └── org/
│ └── joda/
│ └── beans/
│ └── JodaBeans.ini
└── org/
└── joda/
└── beans/
└── ser/
├── Address.xml
├── Address1.packbinstr
├── Address2.binstr
├── Address2.json
├── Address2.simplejson
├── Collections.xml
├── Collections1.binstr
├── Collections1.json
├── Collections1.packbinstr
├── Collections1.refbinstr
├── Collections2.binstr
├── Collections2.json
├── Collections2.simplejson
├── ImmAddress.xml
├── ImmAddress1.binstr
├── ImmAddress1.json
├── ImmAddress1.packbinstr
├── ImmAddress1.refbinstr
├── ImmAddress1.simplejson
├── ImmAddress2.binstr
├── ImmAddress2.json
├── ImmAddress2.simplejson
├── ImmAddressCached1.packbinstr
├── ImmArrays1.binstr
├── ImmArrays1.json
├── ImmArrays1.packbinstr
├── ImmArrays1.refbinstr
├── ImmArrays1.simplejson
├── ImmArrays2.binstr
├── ImmArrays2.json
├── ImmArrays2.simplejson
├── ImmOptional.xml
├── ImmOptional1.packbinstr
├── ImmOptional1.refbinstr
├── ImmOptional2.binstr
├── ImmOptional2.json
├── ImmOptional2.simplejson
└── SimpleJson2.simplejson
================================================
FILE CONTENTS
================================================
================================================
FILE: .coderabbit.yaml
================================================
language: en-GB
tone_instructions: ''
early_access: false
enable_free_tier: true
reviews:
profile: chill
request_changes_workflow: true
high_level_summary: true
high_level_summary_placeholder: '@coderabbitai summary'
auto_title_placeholder: '@coderabbitai'
review_status: true
commit_status: true
poem: false
collapse_walkthrough: true
sequence_diagrams: false
changed_files_summary: true
labeling_instructions: []
path_filters:
- '**/*'
- '**/gen/**'
- '!**/test/**/gen/**'
- '!**/.git/**'
- '!**/target/**'
path_instructions:
- path: '**/*.java'
instructions: |
- Review code using Java 21 standards, taking into account the rules defined by `src/main/checkstyle/checkstyle.xml`.
- Validate that code indentation uses spaces, not tabs, with an indent of multiple of 4.
- Validate that immutable local variables are not annotated with `final` unless the variable is required for use in an inner class.
- Favour use of `var` keyword for type declarations. `var` may also be used when the value is a cast `null`.
- Use a coding standard where multi-line expressions have operators and tenary separators at the end of line.
- Propose changes that only use the Java 21 API, not the API of Guava.
- The pattern matching `instanceof` expression safely handles `null`, returning `false`.
- path: '**/main/java/**/*.java'
instructions: |
- This project is mature and must provide a stable backwards-compatible public Java API.
- In the 'Walkthrough' section, you must always provide a list of up to 25 changes to the public Java API that will affect end users.
If there are no changes, you must explicitly state that there are no changes to the public Java API in this PR.
The public Java API is defined as public and protected methods on public classes, plus the file `module-info.java`.
Provide the list by deeply analysing code flow, which incudes analysing code flow through private methods and calls to Guava and Java 21.
Changes to be reported on include:
- New or removed methods in the public Java API
- Changes to method return types or parameter types in the public Java API
- Changes to method behaviour in the public Java API that might affect consumers
- This project uses `System.out.println` instead of logging
- This project tends to prefer `for` loops to streams for performance reasons, however either form is acceptable.
Do not make suggestions to change between streams and for loops or vice versa.
- path: '**/test/java/**/*.java'
instructions: |
For test code, focus on:
- Correctness of test assertions
- Test coverage of edge cases
- Clear test naming and documentation
- Encourage test methods to be package-scoped where possible
- Be more lenient with code style and minor optimisations
abort_on_close: true
auto_review:
enabled: true
auto_incremental_review: true
ignore_title_keywords: []
labels: []
drafts: false
base_branches:
- 'main'
tools:
shellcheck:
enabled: true
ruff:
enabled: false
markdownlint:
enabled: true
github-checks:
enabled: true
timeout_ms: 90000
languagetool:
enabled: true
enabled_only: false
level: default
enabled_rules: []
disabled_rules:
- EN_UNPAIRED_BRACKETS
enabled_categories: []
disabled_categories:
- TYPOS
- TYPOGRAPHY
- CASING
biome:
enabled: true
hadolint:
enabled: false
swiftlint:
enabled: true
phpstan:
enabled: false
level: default
golangci-lint:
enabled: false
yamllint:
enabled: true
gitleaks:
enabled: true
checkov:
enabled: false
detekt:
enabled: false
eslint:
enabled: true
rubocop:
enabled: false
buf:
enabled: false
regal:
enabled: false
actionlint:
enabled: true
pmd:
enabled: true
cppcheck:
enabled: false
semgrep:
enabled: true
circleci:
enabled: true
ast-grep:
packages: []
rule_dirs: []
util_dirs: []
essential_rules: true
chat:
auto_reply: true
knowledge_base:
opt_out: false
learnings:
scope: auto
issues:
scope: auto
jira:
project_keys: []
linear:
team_keys: []
pull_requests:
scope: auto
================================================
FILE: .github/FUNDING.yml
================================================
github: jodastephen
open_collective: joda
tidelift: maven/org.joda:joda-beans
# https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/displaying-a-sponsor-button-in-your-repository
================================================
FILE: .github/SECURITY.md
================================================
# Security Policy
## Supported Versions
If a security issue occurs, only the latest versions of v3.x and v2.x are guaranteed to be patched.
Consideration will be given to updating the v1.x line, however this is not guaranteed.
## Reporting a Vulnerability
To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure.
================================================
FILE: .github/dependabot.yml
================================================
# Dependabot config
version: 2
updates:
- package-ecosystem: "maven"
directory: "/"
schedule:
interval: weekly
time: "02:30"
open-pull-requests-limit: 20
================================================
FILE: .github/maven-settings.xml
================================================
central-publish${env.MAVEN_CENTRAL_USERNAME}${env.MAVEN_CENTRAL_PASSWORD}github${env.GITHUB_TOKEN}
================================================
FILE: .github/workflows/build.yml
================================================
name: Build
on:
push:
branches:
- '*'
pull_request:
branches:
- 'main'
schedule:
- cron: '41 19 * * 2'
permissions:
contents: read
jobs:
build:
permissions:
security-events: write # for github/codeql-action
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: 21
distribution: 'temurin'
cache: 'maven'
- name: Maven version
run: |
mkdir -p ./.mvn
echo "-e" >> ./.mvn/maven.config
echo "-B" >> ./.mvn/maven.config
echo "-ntp" >> ./.mvn/maven.config
echo "-DtrimStackTrace=false" >> ./.mvn/maven.config
echo "--settings" >> ./.mvn/maven.config
echo "$( pwd )/.github/maven-settings.xml" >> ./.mvn/maven.config
mvn --version
mkdir -p target
#------------------------------------------------------------------------
- name: Initialize CodeQL
uses: github/codeql-action/init@v3
with:
languages: java
- name: Maven build
run: |
mvn install site -Doss.build
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3
================================================
FILE: .github/workflows/release.yml
================================================
name: Release
on:
push:
tags:
- 'release*'
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
ref: "main"
fetch-tags: true
- name: Setup git
run: |
git config --global user.name "Stephen Colebourne (CI)"
git config --global user.email "scolebourne@joda.org"
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: 21
distribution: 'temurin'
cache: 'maven'
- name: Maven version
run: |
mkdir -p ./.mvn
echo "-e" >> ./.mvn/maven.config
echo "-B" >> ./.mvn/maven.config
echo "-ntp" >> ./.mvn/maven.config
echo "-DtrimStackTrace=false" >> ./.mvn/maven.config
echo "--settings" >> ./.mvn/maven.config
echo "$( pwd )/.github/maven-settings.xml" >> ./.mvn/maven.config
mvn --version
mkdir -p target
#------------------------------------------------------------------------
- name: Maven install
run: |
mvn clean install
- name: Maven release
env:
MAVEN_CENTRAL_USERNAME: ${{ secrets.MAVEN_CENTRAL_USERNAME }}
MAVEN_CENTRAL_PASSWORD: ${{ secrets.MAVEN_CENTRAL_PASSWORD }}
MAVEN_GPG_PASSPHRASE: ${{ secrets.RELEASES_GPG_PASSPHRASE }}
MAVEN_GPG_KEY: ${{ secrets.RELEASES_GPG_PRIVATE_KEY }}
GITHUB_TOKEN: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
run: |
mvn release:clean release:prepare release:perform
- name: Update website
run: |
git tag websiterelease
git push origin websiterelease
- name: Delete release tag
if: "always()"
run: |
git tag --delete "${GITHUB_REF_NAME}" || true
git push --delete origin "${GITHUB_REF_NAME}" || true
================================================
FILE: .github/workflows/website.yml
================================================
name: Website
on:
push:
tags:
- 'website*'
permissions:
contents: write
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
token: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
ref: ${{ github.ref }}
fetch-tags: true
- name: Setup git
run: |
git config --global user.name "Stephen Colebourne (CI)"
git config --global user.email "scolebourne@joda.org"
- name: Set up JDK
uses: actions/setup-java@v4
with:
java-version: 21
distribution: 'temurin'
cache: 'maven'
- name: Maven version
run: |
mkdir -p ./.mvn
echo "-e" >> ./.mvn/maven.config
echo "-B" >> ./.mvn/maven.config
echo "-ntp" >> ./.mvn/maven.config
echo "-DtrimStackTrace=false" >> ./.mvn/maven.config
echo "--settings" >> ./.mvn/maven.config
echo "$( pwd )/.github/maven-settings.xml" >> ./.mvn/maven.config
mvn --version
mkdir -p target
#------------------------------------------------------------------------
- name: Maven site
run: |
mvn install site
- name: Checkout website
uses: actions/checkout@v4
with:
token: ${{ secrets.PERSONAL_GITHUB_TOKEN }}
repository: JodaOrg/jodaorg.github.io
path: target/jodaorg.github.io
ref: "main"
- name: Update website
run: |
cd target/jodaorg.github.io
git status
rm -rf joda-beans/
cp -R ../site joda-beans/
git add -A
git status
git commit --message "Update joda-beans from CI: $GITHUB_ACTION"
git push origin main
- name: Delete website tag
if: "always()"
run: |
git tag --delete "${GITHUB_REF_NAME}" || true
git push --delete origin "${GITHUB_REF_NAME}" || true
================================================
FILE: .gitignore
================================================
/bin/
/target/
*.log
/tests/
/test-output/
.checkstyle
.classpath
.project
/.settings/
.idea
*.iml
*.class
================================================
FILE: LICENSE.txt
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: NOTICE.txt
================================================
Joda Beans
Copyright 2001-present Stephen Colebourne
This product includes software developed by
Joda.org (https://www.joda.org/).
================================================
FILE: README.md
================================================
Joda-Beans
------------
Joda-Beans provides a small framework that adds properties to Java, greatly enhancing JavaBeans.
An API is provided that defines a bean and property model, together with a code generator to make it work in practice.
The key concept is to allow each property on a bean to be accessed as an object.
This enables technologies such as XPath, XML conversion, DB mappings, WebApp validation and Swing bindings.
Joda-Beans is licensed under the business-friendly [Apache 2.0 licence](https://www.joda.org/joda-beans/licenses.html).
### Why Joda Beans?
Joda-Beans has been created to plug a gap in the Java language - properties.
The concept of properties is familiar to those coding in almost every other modern language.
Java stands alone in its pursuit of the terrible JavaBean approach, and personally I believe that
properties should have been added to Java before generics and closures.
JavaBeans are typically created by manual coding or one-off IDE generation, such as by Eclipse.
The same approach is taken to the creation of equals and hashCode methods.
However, none of these approaches provides for a simple and fast mechanism to query a bean for the properties it exposes.
Joda-Beans provides a solution. As a developer, you just write the fields much as you would today.
Then you add annotations to the bean and properties.
Finally, you run a code generator, which creates the get/set methods plus framework methods that allow the properties
to be effectively queried.
If you use Eclipse and the Joda-Beans Maven plugin, the bean will be regenerated automatically on save.
A key point is that the code generator may be run again and again on the Java file, and is non-destructive.
See these sample classes used for testing -
[a simple user account class](https://github.com/JodaOrg/joda-beans/blob/v2.0/src/test/java/org/joda/beans/gen/UserAccount.java#L32),
[example usage](https://github.com/JodaOrg/joda-beans/blob/v2.0/src/test/java/org/joda/beans/Examples.java#L22),
[example of validation](https://github.com/JodaOrg/joda-beans/blob/v2.0/src/test/java/org/joda/beans/gen/ValidateBean.java#L33).
### Documentation
Various documentation is available:
* The [home page](https://www.joda.org/joda-beans/)
* The helpful [user guide](https://www.joda.org/joda-beans/userguide.html)
* The [Javadoc](https://www.joda.org/joda-beans/apidocs/index.html)
* The change notes for the [releases](https://www.joda.org/joda-beans/changes-report.html)
* The [related projects](related.html) including Maven, Gradle and IntelliJ integration
### Releases
The 3.x branch is compatible with Java SE 21 or later.
The 2.x branch is compatible with Java SE 8 or later.
v3.x releases are mostly compatible with v2.x releases,
see the [releases notes](https://www.joda.org/joda-beans/changes-report.html) for details.
Deprecated methods have been removed.
Joda-Beans depends on [Joda-Convert](https://www.joda.org/joda-convert/).
There are a number of [optional dependencies](https://www.joda.org/joda-beans/dependencies.html) which help with integration.
Available in the [Maven Central repository](https://search.maven.org/search?q=g:org.joda%20AND%20a:joda-beans&core=gav)
For Java SE 6 compatibility, use [release 1.14](https://github.com/JodaOrg/joda-beans/releases/tag/v1.14).
There are only [minor incompatibilities](https://www.joda.org/joda-beans/migration.html) with the 1.x codebase.

### For enterprise
Available as part of the Tidelift Subscription.
Joda and the maintainers of thousands of other packages are working with Tidelift to deliver one enterprise subscription that covers all of the open source you use.
If you want the flexibility of open source and the confidence of commercial-grade software, this is for you.
[Learn more](https://tidelift.com/subscription/pkg/maven-org-joda-joda-beans?utm_source=maven-org-joda-joda-beans&utm_medium=github)
### Support
Please use [Stack Overflow](https://stackoverflow.com/search?q=joda-beans) for general usage questions.
GitHub [issues](https://github.com/JodaOrg/joda-beans/issues) and [pull requests](https://github.com/JodaOrg/joda-beans/pulls)
should be used when you want to help advance the project.
Any donations to support the project are accepted via [OpenCollective](https://opencollective.com/joda).
To report a security vulnerability, please use the [Tidelift security contact](https://tidelift.com/security).
Tidelift will coordinate the fix and disclosure.
### Release process
* Update version (index.md, changes.xml)
* Commit and push
* `git push origin HEAD:refs/tags/release`
* Code and Website will be built and released by GitHub Actions
Release from local:
* Ensure `gpg-agent` is running
* `mvn clean release:clean release:prepare release:perform`
================================================
FILE: RELEASE-NOTES.txt
================================================
Joda-Beans
================================================
Joda-Beans is a library that provides full bean and property support for the JDK.
The release runs on Java 21 or later.
See https://www.joda.org/joda-beans/changes-report.html for changes
Feedback
--------
Feedback is best received using GitHub issues and Pull Requests.
https://github.com/JodaOrg/joda-beans/
The Joda team
================================================
FILE: pom.xml
================================================
4.0.0org.jodajoda-beansjarJoda-Beans3.0.0-SNAPSHOTBeans and Properties, compatible with Java 21+https://www.joda.org/joda-beans/2007Apache License, Version 2.0https://www.apache.org/licenses/LICENSE-2.0.txtrepoJoda.orghttps://www.joda.orgGitHubhttps://github.com/JodaOrg/joda-beans/issues/scm:git:https://github.com/JodaOrg/joda-beans.gitscm:git:https://github.com/JodaOrg/joda-beans.githttps://github.com/JodaOrg/joda-beansHEADjodastephenStephen ColebourneProject Lead0https://github.com/jodastephenbcamelhttps://github.com/bcamelbiteytechhttps://github.com/biteytechHack Kampbjornhttps://github.com/hackmannChris Kenthttps://github.com/cjkentmediahypehttps://github.com/mediahypeWill Nicholsonhttps://github.com/wjnicholsonMartynas Sateikahttps://github.com/martynassateikaAndreas Schillinghttps://github.com/andreas-schillingtroshaninhttps://github.com/troshaninKevin Vellahttps://github.com/legasrc/main/resourcesMETA-INF${project.basedir}LICENSE.txtNOTICE.txtorg.apache.maven.pluginsmaven-enforcer-pluginenforce-mavenenforce3.8.0[21,)org.apache.maven.pluginsmaven-compiler-plugindefault-testCompile--add-modulesjava.desktop--add-readsorg.joda.beans=java.desktoporg.apache.maven.pluginsmaven-surefire-plugindefault-testtrue--add-modules java.desktop --add-reads org.joda.beans=java.desktop --add-exports org.joda.beans/org.joda.beans.sample=org.joda.converttest-without-modulestesttestfalseorg.apache.maven.pluginsmaven-release-plugin-Doss.build -Doss.repotruev@{project.version}trueorg.kohsukegithub-api${github-api.version}org.apache.maven.pluginsmaven-assembly-plugin${maven-assembly-plugin.version}org.apache.maven.pluginsmaven-checkstyle-plugin${maven-checkstyle-plugin.version}org.apache.maven.pluginsmaven-changes-plugin${maven-changes-plugin.version}org.apache.maven.pluginsmaven-clean-plugin${maven-clean-plugin.version}org.apache.maven.pluginsmaven-compiler-plugin${maven-compiler-plugin.version}org.apache.maven.pluginsmaven-deploy-plugin${maven-deploy-plugin.version}org.apache.maven.pluginsmaven-dependency-plugin${maven-dependency-plugin.version}org.apache.maven.pluginsmaven-enforcer-plugin${maven-enforcer-plugin.version}org.apache.maven.pluginsmaven-gpg-plugin${maven-gpg-plugin.version}org.apache.maven.pluginsmaven-install-plugin${maven-install-plugin.version}org.apache.maven.pluginsmaven-jar-plugin${maven-jar-plugin.version}org.apache.maven.pluginsmaven-javadoc-plugin${maven-javadoc-plugin.version}org.apache.maven.pluginsmaven-jxr-plugin${maven-jxr-plugin.version}org.apache.maven.pluginsmaven-plugin-plugin${maven-plugin-plugin.version}org.apache.maven.pluginsmaven-pmd-plugin${maven-pmd-plugin.version}org.apache.maven.pluginsmaven-project-info-reports-plugin${maven-project-info-reports-plugin.version}org.apache.maven.pluginsmaven-release-plugin${maven-release-plugin.version}org.apache.maven.pluginsmaven-repository-plugin${maven-repository-plugin.version}org.apache.maven.pluginsmaven-resources-plugin${maven-resources-plugin.version}org.apache.maven.pluginsmaven-source-plugin${maven-source-plugin.version}org.apache.maven.pluginsmaven-surefire-plugin${maven-surefire-plugin.version}org.apache.maven.pluginsmaven-surefire-report-plugin${maven-surefire-report-plugin.version}org.apache.maven.pluginsmaven-toolchains-plugin${maven-toolchains-plugin.version}org.jacocojacoco-maven-plugin${jacoco-maven-plugin.version}com.github.spotbugsspotbugs-maven-plugin${spotbugs-maven-plugin.version}org.apache.maven.pluginsmaven-site-plugin${maven-site-plugin.version}trueattach-descriptorattach-descriptoren,deorg.joda.externalreflow-velocity-tools1.2org.jodajoda-convert${joda-convert.version}com.google.guavaguava${guava.version}truecom.google.guavalistenablefuturecom.google.errorproneerror_prone_annotationscom.google.j2objcj2objc-annotationsorg.checkerframeworkchecker-qualcom.google.code.findbugsjsr305org.jodajoda-collect${joda-collect.version}trueorg.junit.jupiterjunit-jupiter${junit.version}testorg.assertjassertj-core${assertj.version}testorg.apache.maven.pluginsmaven-project-info-reports-plugin${maven-project-info-reports-plugin.version}ci-managementdependenciesdependency-infoissue-managementlicensesteamscmsummaryorg.apache.maven.pluginsmaven-checkstyle-plugin${maven-checkstyle-plugin.version}falsefalsefalsemodule-info.javaorg.apache.maven.pluginsmaven-javadoc-plugin${maven-javadoc-plugin.version}javadoc21org.apache.maven.pluginsmaven-surefire-report-plugin${maven-surefire-report-plugin.version}trueorg.apache.maven.pluginsmaven-changes-plugin${maven-changes-plugin.version}changes-reportorg.apache.maven.pluginsmaven-pmd-plugin${maven-pmd-plugin.version}100${maven.compiler.release}module-info.javacom.github.spotbugsspotbugs-maven-plugin${spotbugs-maven-plugin.version}org.jacocojacoco-maven-plugin${jacoco-maven-plugin.version}reportoss-buildoss.buildorg.apache.felixmaven-bundle-plugin${maven-bundle-plugin.version}bundle-manifestprocess-classesmanifest${project.version}${joda.osgi.packages}${joda.osgi.require.capability}
<_fixupmessages>"Classes found in the wrong directory"; restrict:=error; is:=ignore
trueorg.apache.maven.pluginsmaven-jar-plugin${project.build.outputDirectory}/META-INF/MANIFEST.MFtruetrueorg.apache.maven.pluginsmaven-javadoc-pluginattach-javadocspackagejar21org.apache.maven.pluginsmaven-source-pluginattach-sourcespackagejar-no-forkorg.apache.maven.pluginsmaven-checkstyle-pluginrun-checkstyleprocess-sourcescheckstylemodule-info.javacom.puppycrawl.toolscheckstyle${checkstyle.version}org.jacocojacoco-maven-pluginjacoco-initializeprepare-agentjacoco-sitepackagereportgithub-actionenv.GITHUB_ACTIONStruebcrelease-artifactsoss.repoorg.apache.maven.pluginsmaven-assembly-pluginfalsesrc/main/assembly/dist.xmlgnumake-assemblyinstallsingleorg.apache.maven.pluginsmaven-gpg-pluginsign-artifactsverifysignorg.sonatype.centralcentral-publishing-maven-plugin${central-publishing-maven-plugin.version}truecentral-publish${project.name}${joda.publish.auto}${joda.publish.wait}de.jutziggithub-release-plugin${github-release-plugin.version}Release v${project.version}See the [change notes](https://www.joda.org/joda-beans/changes-report.html#a${project.version}) for more information.v${project.version}true${project.build.directory}joda-beans*-dist.tar.gzjoda-beans*-dist.zipgithub-releasesdeployrelease3.27.333.4.8-jre2.0.03.0.15.13.4org.joda.beans.*osgi.ee;filter:="(&(osgi.ee=JavaSE)(version=${maven.compiler.release}))"falsevalidated3.7.16.0.02.12.13.4.03.4.03.13.03.8.13.1.33.5.03.2.73.1.33.4.23.11.23.6.03.15.13.24.03.6.23.1.12.43.3.13.12.13.3.13.5.33.5.33.2.00.8.01.3261.6.00.8.120.11.10.15.14.8.6.621truefalsetruenone10.23.1src/main/checkstyle/checkstyle.xmlfalseUTF-8UTF-8
================================================
FILE: src/changes/changes.xml
================================================
ChangesStephen Colebourne
Major version based on Java SE 21.
Mostly compatible with v2.x.
Deprecated methods have been removed.
Allow Java records to become beans.
Add `RecordBean` interface that can be implemented by records.
Add `LinkedByteArrayOutputStream`, which is like `ByteArrayOutputStream` but faster.
Add `ResolvedType`, which allows generic type information to be managed in a simple way.
Potentially incompatible change:
Manual equals, hashCode and toString methods must now be located *before* the autogenerated block.
This change allows nested classes to be written with their own equals, hashCode and toString methods,
so long as the nested class is written *after* the autogenerated block.
It is expected that most uses of Joda-Beans already have the equals, hashCode and toString methods
before the autogenerated block and therefore will be unaffected.
Add a new binary format.
This change adds a third binary format, with a focus on size and performance.
In testing it produces binary files similar or slightly smaller than the referencing binary format,
but with faster serialization and deserialization. This solves a performance problem with the referencing
format whereby it tried to deduplicate all beans, even those with very large hash codes.
As part of this change, callers should now explicitly select which binary format they want using `JodaBeanBinFormat`.
Potentially incompatible change:
The standard and referencing binary formats now support null as a map key.
Potentially incompatible change:
The referencing binary format no longer deduplicates collections.
The old format can still be parsed successfully.
Potentially incompatible change:
The standard binary and JSON formats now handle `Iterable` as a collection type.
Incompatible change:
The JSON serialization formats have changed for primitive arrays.
Instead of a Joda-Convert formatted string, the array is output as a list of primitives.
This also applies to multi-dimensional arrays.
This is a much more natural JSON format.
The old format can still be parsed successfully.
Incompatible change:
The JSON serialization formats have changed requiring fewer @meta and @type annotations.
For example, where the type of the collection is Object,
previously a String value was explicitly typed as a String, now the type is implicit.
This is a much more natural JSON format.
The old format can still be parsed successfully.
Incompatible change:
The simple JSON serialization format now uses a string instead of null for NaN for consistency.
The new configuration 'JodaBeanJsonNumberFormat' can be used to control how NaN and Infinity are output.
As part of this change, the extended literals from 'The JSON5 Data Interchange Format' can be used if desired.
Potentially incompatible bug fix:
Properties of type 'boolean[]' and 2-dimensional arrays are now cloned by default in immutable beans
in line with existing behaviour. Cloning is opt-in for mutable beans using new settings on `PropertyDefinition`.
Potentially incompatible bug fix:
Binary and JSON parsers now accept the formats produced by v3.x.
Certain edge cases now succeed when previously an exception would have been thrown.
Fix code generation for property names that clash with code generated method parameters.
Properties named `obj`, `other` or `propertyName` caused problems.
These are now prefixed by `this` to avoid the clash.
Fix `BeanAssert` to output the correct message.
Previously there was no check for equals at the property level, nor were arrays properly converted to `String`.
Fix code generation of light beans for `short`, `byte` and `char` fields.
Allow deserialization to handle numbers greater than the capacity of an int.
Add `PropertyPath` class, allowing multi-stage property lookups.
New methods on MetaBean and MetaProperty to query an annotation, returning Optional.
DirectBean annotation lookup now handles derived properties correctly.
The jar file is now a multi-release jar file, with the module-info file moved.
The classic jar file (without module-info.class) is no longer produced.
Allow generics in metaImplements.
Remove erroneous assertj dependency.
Add 'metaImplements' bean definition option that allows meta beans to implement an interface.
Allow IDEs to generate @Override tags without Joda-Beans removing them on regeneration.
Switch master to main.
Switch LGTM to CodeQL.
Fix bug in referencing deserialization.
Update dependencies.
Avoid NPE in `MetaBeans`.
Update Guava dependency.
Add 'eol' command line argument to control the end-of-line character.
Ensure meta-bean only registered once.
Provide ability to copy a bean to a builder of a different type.
See JodaBeanUtils.copy(Bean, Class).
Add MetaBeanProvider annotation for more flexible meta-bean lookup.
Fix mutable beans where the subclass has no properties.
Fixes #210, #221.
Fix binary serialization of Joda-Convert types with intermediate interfaces in referencing format.
Fix toString() to include derived properties.
Handle repeated annotations more cleanly.
Call JodaBeansUtils.toString() on all properties, not just the last.
Fix manual builders when used with minimal style.
Add smart reader, that dynamically works out the format of the input.
Provide the ability to manually write a builder.
New command line flag -generated to add @Generated annotation.
Fixes #209, #149
Change XML parsing to share factory.
The JDK bug was fixed many years ago now, please use JDK 8u20 or later to avoid issues.
Fix referencing binary format for serialized nulls.
Fix referencing binary format for serialized nulls.
Fix referencing binary format for interfaces serialized via Joda-Convert.
Update Joda-Convert version.
Add referencing binary format that typically uses less space.
Ensure that annotations are parsed correctly on fields.
Ensure that all annotations are available at runtime.
Ensure that builders on mutable beans are handled correctly.
Create `toBuilder()` methods and fix case where empty parent bean didn't compile.
Fix handling of deprecated properties.
Ensure that Javadoc tag is not output twice.
Move the tag to be output last, after other tags.
Add ability to serialize XML to an `Appendable`.
Deprecate existing `writeToBuffer()` methods.
See #196.
Add Tidelift commercial support and security policy.
Allow deserializers to be registered in config files.
Avoid NullPointerException in finally block.
Parse class headers spread over multiple lines.
Fixes #191.
Update Guava and Joda-Collect versions.
Allow primitive integral types to be deserialized into floating point properties.
Fixes #190.
Ensure tests and functionality work correctly on Java 9.
Fix light and minimal beans to respect aliases.
Aliases are useful for handling the rename of properties.
Fixes #187.
Add classic jar file for those that can't handle module-info.class.
Fixes #188.
Remove integration projects - Freemarker, Kryo, Mongo.
These are now available as separate Maven artifacts, see https://github.com/JodaOrg/joda-beans-integrate.
Add module-info for Java 9.
Fixes #180.
Allow serialization of derived properties.
Use JodaBeanSer::withIncludeDerived(true).
Fixes #183.
Change serialization format of simple JSON.
Primitive arrays are now output in standard JSON format, not as a string.
Any byte arrays are still output as base-64.
Simple map format was also changed to retain the arrays.
Fixes #186.
Handle double space in field definitions.
Fixes #182.
Handle wildcards better when looking up generic types.
Fixes #185.
Avoid NPE when parsing JSON.
If the generic type of the key could not be decoded, NPE could result.
Fixes #184.
Fix error message for table/grid.
Fixes #179.
Fix serialization issues for collections.
ImmutableSortedMap now works.
Collections where the generic is `Comparable` now work.
Update and redesign build to support Java 9.
Fix cached hash code to be transient.
It must not be serialized.
Fixes #177.
Fix minimal and light beans.
Code erroneously assumed reflection returns fields in source code order.
Fixes #176.
Ensure that properties stay in order.
Use LinkedHashMap instead of HashMap where necessary.
Move to Java 8.
Change light beans from reflection to method handles.
Change minimal beans to not have generated meta-bean class and disallow subclasses.
Fixes #155.
Use diamond operators in generated code.
Fixes #5.
Add @SafeVarargs annotation.
Fixes #156.
Change BeanBuilder.get to use meta property type.
Fixes #152.
Remove comments for Clover ON/OFF.
Use the AUTOGENERATED START/END comments instead.
Fixes #157.
MetaBean must pass type of bean to builder.
This is needed when the meta-bean is not generated.
Fixes #158.
Ensure light beans default empty collections.
Fixes #148.
Remove deprecated methods.
Additional meta-bean methods - isBuildable(), of(Class), annotations(), annotation(Class).
Fixes #161.
Register meta-beans via MetaBean.register(). Deprecate old way on JodaBeanUtils.
Fixes #166.
Add methods to assist with test coverage.
Force coverage of Joda-Beans branches so the coverage percentage is more meaningful.
Add `Automatic-Module-Name` into `MANIFEST.MF`.
Locks in module name for Java SE 9.
Fixes #175.
Generate property change as `final transient`.
Fixes #173.
Handle multi-line annotations after `@PropertyDefinition`.
This simply looks for a comma at the end of the previous line, which isn't perfect but better than nothing.
Fixes #174.
Add lenient mode for deserialization, see `SerDeserializers`.
This allows unknown properties and some invalid types to be ignored.
Fixes #170.
Support derived properties on light and minimal beans.
Fixes #169.
Avoid warnings with generated code setString() and setAll().
Fixes #168.
Add notBlank validation.
Fixes #167.
Ensure builder calls super constructor in hierarchy.
Fixes #150.
Rename config file from "jdk6" to "jdk".
Fixes #163.
ToString style of 'omit' did not affect builder.
Fixes #164.
Serialize to/from a Map of Maps.
Fixes #159.
Deprecate PropertyMap, use JodaBeanUtils.flatten(bean) or BasicPropertyMap.of(bean).
Deprecate BeanQuery, use functional interfaces in Java SE 8.
Deprecate BeanBuilder methods - setString() and setAll().
Redesign reflective meta-bean.
Fixes #160.
JSON/binary serialization fails to read in a double[][] written with meta type.
Fixes #147.
Allow mutable light beans to control constructor scope.
Fixes #145.
Generated factory methods do not have Javadoc @return.
Fixes #146.
Ensure light bean builder handles arbitrary meta property implementations.
Fixes #144.
Avoid generating methods that have no advantage in private builders.
Fixes #143.
Light bean setters fail to work via bean abstraction.
Fixes #142.
Light meta bean field should be final.
Fixes #141.
Scope of meta bean and builder should match scope of main bean.
Fixes #140.
Add deserializer providers, to allow more extensibility in deserialization.
Fixes #128.
Extend concept of "light" beans to mutable.
Light beans generate minimal code - no meta bean or builder.
Fixes #139.
Avoid NPE for mutable beans with builder.
Fixes #138.
Allow clone methods on immutable beans.
Allow clone methods to be skipped during generation.
Fixes #135.
Enhance Guava deserialization when using certain immutable collection types.
Fixes #131.
Incorrect config file for JDK 6.
Fixes #134.
Provide integration with Kryo serialization.
Fixes #130.
Add generation of static factory method.
Fixes #123.
Allow scope of meta-bean to be controlled.
Fixes #127.
Optional properties on light beans did not report the correct property type.
This caused serialization to fail.
Also fix field-based access problems due to lack of setAccessible.
Fixes #126.
Handle JSON parsing where integer can be converted safely to double or float.
Fixes #122.
Add support for EnumSet.
Fixes #125.
Change equals/hashCode/toString to use fields, not getters, for immutable beans.
Allow equals/hashCode/toString to be controlled , including selectively omitted.
Fixes #118, #121.
Provide ability to generate ConstructorProperties annotation.
Fixes #120.
Allow tolerance to be set when comparing beans using BeanAssert.
Additional methods on JodaBeanUtils provides tools for manual equals() methods.
Fixes #117.
Make bean parser more lenient.
Handle open brace immediately following Bean or ImmutableBean in an implements clause.
Fixes #116.
Use configured prefix for cachedHashCode and propertyChangeSupport.
Fixes #115.
Avoid null check in array clone getters where possible.
Fixes #114.
Fix light-weight immutable bean generation.
Generation needs to add call to register the meta-bean.
Constructor location logic is now more lenient to handle interface/class separation.
Fixes #111.
Fix XML to read/write interface base keys.
Handle case where interface does note extend Bean interface.
Fixes #119.
Add light-weight immutable bean generation.
Light-weight code generation using reflection to implement the bean methods.
No Meta class or Builder is generated.
Fixes #111.
Add basic support for bound properties.
Implementation only handles non-final properties on mutable beans.
Fixes #78.
Support package, protected and public scoped immutable constructors.
Fixes #107.
Support package-scoped builder classes.
Fixes #109.
Support package-scoped getters/setters.
Fixes #108.
Allow immutable builder property type to be manually controlled.
Fixes #103.
Enhance generation of varargs builder methods.
Support "List<? extends Foo>" and "List<?>"
Fixes #104.
Generate documentation for builder methods based on user-written docs.
Fixes #106.
Fix code generation for immutable beans where there are two generic types and the types are linked.
For example, Foo<A, B extends Comparable<A>>.
Fixes #110.
Enable better test coverage.
Fixes #102.
Optimise JodaBeanUtils for hotspot inlining.
Fixes #101.
Optimise internals of generated builders to use immutable collections.
This avoids unnecessary copying and object creation.
Fixes #96.
Provide details of files changed by code generation.
This allows tooling, such as the maven plugin, to be enhanced.
Fixes #99.
Standard format for exceptions in code generation.
Dedicated exception type allows tooling, such as the maven plugin, to be enhanced.
Fixes #98.
Add related projects page to website.
Fixed parsing of verbose command line flag.
Fixes #97.
Add ImmutablePreBuild annotation.
This handles the case where a property needs to be defaulted from the value of another property.
In most cases, ImmutableDefaults and/or ImmutableValidator are sufficient.
Fixes #95.
Generate serialization version id.
If the class implements Serializable and there is no manual serialVersionUID, then one will be generated.
Fixes #94.
Support Optional properties in serialization.
If an optional property is used, support it in serialization.
This works for everything except collection types.
Fixes #93.
Support Optional return type for getters of nullable properties.
Allows the instance variable of a property to remain nullable (as recommended for Java 8)
but with the getter returning an Optional wrapper.
Simply declare the PropertyDefinition with 'get="optional"'.
Fixes #92.
Avoid including derived properties in equals/hashCode.
Fixes #91.
Add support for protected scope getters and setters.
Fixes #90.
Fix bean generation to handle a lack of spaces in field initializers.
Fixes #87.
Fix bean generation to handle a property of a wildcard list type.
While the need for this is rare, better processing is needed.
The fix requires use of the PropertyDefinition "type" attribute in certain cases.
Fixes #88.
The generated hash codes had a flaw and the algorithm has been changed.
Previously, they used (h += h * 31 + value.hashCode).
Now, they use (h = h * 31 + value.hashCode).
The incorrect version failed to generate unique hash codes when a bean
mostly contained null properties.
This causes all beans to regenerate.
Fixes #89.
Add varargs overrides for collections in immutable builders.
Fixes #85.
Fix code generation of immutable package-scoped beans.
Fixes #86.
Add ability to iterate over all the beans within a bean.
Depth-first iteration handling collections.
Fixes #84.
Fix parsing of class name with extends clause union types.
Generic parameters on second and subsequent union types are not supported.
Fixes #83.
Add alias support to PropertyDefinition.
A simple mechanism to handle property renames.
Fixes #82.
Fix parsing of class name with extends clause generics of type with two generic parameters.
Fixes #81.
Add option to allow property values to be defaulted on immutable beans.
New annotation @ImmutableDefaults allows default values to be set.
Fixes #80.
Add option to allow hash codes to be cached.
New attribute on @BeanDefinition allows caching of hash codes.
Fixes #79.
Reduce scope of serialization helper classes.
MsgPack, MsgPackInput, MsgPackOutput and JodaBeanXml.
Backwards incompatible, but should not have been used.
Add JSON round-trip serialization.
Fixes #75.
Use effective type exposed by Joda-Convert.
Joda-Convert v1.7 exposes the effective type of the converted string.
This can be more useful to use in serialization than the value type.
For example, where a public interface has the `FromString` annotation and non-public subclass has the `ToString`.
Fixes #76.
Better documentation.
Fixes #74.
Fix to add @Override annotation on toBuilder().
Fixes #73.
Fix serialization to handle subclasses of enums.
Fixes #72.
Fix immutable beans with private builders.
Meta-Bean builder() method returned the private buidler.
Fixes #70.
Fix immutable builder setString() method to actually convert from a string.
Fixes #69.
Add JodaBeansUtils.notEmpty(Collection) and JodaBeansUtils.notEmpty(Map).
Fixes #71.
Update docs for v1.0.
Provide @ImmutableValidator to allow immutable constructors to be manually validated.
Fixes #65.
Generate Javadoc param tags for generic types in meta/builder.
Fixes #68.
Add getter/setter style of "field".
As all access is direct to the field, a weird getter/setter can be used.
Fixes #67.
Remove Bean.clone().
Clashes with generic union types.
Immutable beans no longer generate a clone method.
Use JodaBeanUtils.clone(bean) instead.
Fixes #66.
Block immutable beans from using EnumBiMap, EnumHashBiMap, HashBiMap,
EnumMultiset, HashMultiset, LinkedHashMultiset, TreeMultiset,
ArrayListMultimap, LinkedListMultimap, HashMultimap, LinkedHashMultimap, TreeMultimap, SortedSetMultimap
SparseGrid, DenseGrid.
Change Multimap interface to use ArrayListMultimap, not HashMultimap, because ImmutableMultimap is list based.
Fixes #64.
Enable selective use of Override annotation.
Fixes #63.
Undo deprecation of BasicImmutableBeanBuilder.
Fix immutable beans builder method comment.
Fixes #62.
Enhance and fix 2D array support in serialization.
Fixes #61.
Enhance and fix meta-type support in serialization.
Fixes #60.
Add support for Joda-Collect Grid interface.
Fixes #59.
Add support for Guava BiMap interface.
Fixes #58.
Handle collections in clone().
Fixes #55.
Do not clone in getters of mutable beans for arrays and java.util.Date.
Fixes #57.
Add mime types for serialized formats.
Fixes #56.
Add support for Guava Table interface.
Fixes #54.
Immutable subclass builders do not work.
Immutable and builder-based beans will regenerate.
Fixes #53.
Bean builder should have getters.
Immutable and builder-based beans will regenerate.
Fixes #52.
Deprecate BasicImmutableBeanBuilder.
Support three generic parameters.
Fixes #51.
More secure XML parsing.
Add Joda-Bean binary serialization based on MessagePack.
Fixes #49.
More flexible XML parsing wrt Joda-Convert.
Handle a bean that has Joda-Convert annotations added, or vice versa.
Fixes #50.
Invalid code generated for an abstract @ImmutableBean.
Fixes #48.
Guava MultiSet serialized incorrectly.
Was serializing using the set size, not the unique elements size.
Fixes #47.
Choose known types in serialization carefully.
Reduce the set from v0.9.2 as that set of types was too large.
Fixes #46.
Fix BeanComparisonError.
Fixes #45.
Remove encodeClass/decodeClass from main serialization API.
Fixes #44.
Handle refactored beans in deserialization.
Fixes #43.
BasicBeanBuilder get(String) returns builder rather than the requested data.
Backwards incompatible, but the old code is useless so will never have been used.
Fixes #42.
Ensure XML reader property closed.
Fixes #41.
Handle type renames in deserialization.
Fixes #40.
Short types flag not being used in JodaBeanSer.
Fixes #39.
Fix immutable collection copies to preserve comparators.
Affects SortedSet and SortedMap.
Fixes #37.
Remove incorrect suppress unchecked in immutable generic beans.
Fixes #38.
Support partially final beans and immutable subclasses.
This support is complex and not recommended, but sometimes necessary.
Fixes #24.
Recreate XMLInputFactory each time due to JDK bug JDK-8028111.
Fixes #36.
Fix to ensure nested class constructors are private if the type is final.
May cause beans to regenerate.
Fixes #35.
Extend notNull validation to collection properties.
May cause beans to regenerate.
Fixes #34.
Enhance PropertyStyle. Add isReadOnly().
Fixes #33.
Add 'equalIgnoring' utility to compare two beans ignoring one or more properties.
Fixes #32.
XML generation of beans with no fields broken.
Affected COMPACT mode, not PRETTY mode.
Fixes #30.
FlexiMap should retain the order of properties.
Use LinkedHashMap not HashMap.
Fixes #31.
Fix code generation unchecked annotation when no writable properties.
Allow beans to have two generic type parameters. Fixes #21.
Fix code generation of private immutable builders. Fixes #26.
Parse trailing comments on property definitions. Fixes #27.
Add setting to allow immutable builders to be private. Fixes #26.
Avoid code generating two lines next to one another.
Handle extra spaces in class/extends definitions. Fixes #25.
Fix code generation for properties of generic type array.
Where bean is Foo<T> and property is T[].
Also where immutable bean and property is T.
Fixes #22.
Bean toString should process arrays correctly. Fixes #23.
Enhance handling of non-null and non-empty fields especially in immutable beans. See #20.
Immutable beans should handle nullable fields. Fixes #20.
Generate an immutable bean with no properties correctly.
Handle classes that are loaded but not initialized. Fixes #19.
Fix XML parsing of complex map entries.
Handle multi-line class definition. Fixes #17.
Fix FlexiBean serialization. Fixes #18.
SerIteratorFactory off by one bug.
XML format no longer encodes tabs and newlines in elements.
Allow private getters/setters using PropertyDefinition.
Rename XML format map items to 'entry'.
Allow map keys to be beans, using two 'item' elements beneath 'entry'.
Extend analysis of collection/map generic types.
Allow short types to be switched off.
Handle simple types better when defined by unknown interface.
Generate correct Javadoc for builder static method with generics.
Allow known types to be built up during serialization.
Permit XML format to omit root type.
Output Joda-Convert data whenever available.
Move to OSGi generation via Maven plugin.
Add XML round-trip serialization. Fixes #16.
Allows the bean to be converted to and from XML in a human readable format.
Enhance FlexiBean and MapBean. Fixes #15.
These now work more like the original intention.
Properties are always created on demand.
FlexiBean property names are now validated to a minimal format.
Identify Derived and Immutable properties at runtime. Fixes #14.
Rename readWrite() to style() and PropertyReadWrite to ProperyStyle.
Some existing beans may regenerate.
Generate final classes for final beans. Fixes #13.
Some existing beans may regenerate.
Parse annotations above @PropertyDefinition as well as those below. Fixes #10.
Some existing beans may regenerate.
Add support for clone on beans.. Fixes #12.
All existing beans will regenerate.
Add support for immutable beans. Fixes #11.
All existing beans will regenerate.
Move location of equals/hashCode/toString methods in generation.
All existing beans will regenerate.
Allow generated beans to implement interface, rather than extend class. Fixes #9.
Move propertyGet/propertySet/validate into meta-bean
All existing beans will regenerate.
Generate toString() methods. Fixes #8.
All existing beans will regenerate.
Optimize performance of generated equals for primitive numbers.
Some existing beans will regenerate.
Home page at GitHub.
Adjust code generation so can reformat in Eclipse without changing generated code.
Existing beans will regenerate, even though the only change is one blank line.
Add checkstyle
Change to use m2e Maven Eclipse
Fix indentation issue in metaPropertyMap field.
Existing beans will regenerate, even though the only change is indentation.
Refactor BeanCodeGen to allow it to be used from tools.
Fix command line arguments - -v -> -verbose.
Add getString() and setString() overrides that take a StringConvert instance.
Add metaXxx(Class) method to work around Eclipse/javac/Intellij generics compiler issues.
Existing beans will need regenerating.
Allow derived property to be abstract or final.
Set correct read/write flag for final fields.
Make generics more correct.
Add builder methods based on meta-property.
Move example code to correct location.
Allow a property to be named 'map'.
Handle empty comments correctly.
Extend builder to support setting by string.
Update to Joda-Convert v1.2 and use new feature to improve string conversion.
DirectBean no longer extends BasicBean to simplify the hierarchy.
Add BeanQuery and comparator support.
Handle generic subclasses better in JodaBeanUtils collection/map type extraction.
Handle arrays in JodaBeanUtils equals method.
Fix JodaBeanUtils to handle collections and sets as well as lists.
Fix generation of non-collection final properties.
Add JodaBeanUtils.clone().
Add JodaBeanUtils.metaBean(), to lookup meta-bean by class.
This requires regeneration of direct beans.
Improve generation of imports.
This may require regeneration of direct beans.
Handle write-only properties better.
This requires regeneration of direct beans.
Allow conversion to and from a standard format string from meta-property.
Add basic validation support.
Add derived property annotation and support.
Add BeanBuilder concept.
Refactor to improve equals/hashCode performance.
Fix property/meta-property equals/hashCode.
Enhance meta-property map.
Minor fixes.
Handle generic subclass of a generic class.
Handle subclass of a generic class.
Initial version.
================================================
FILE: src/main/assembly/dist.xml
================================================
disttar.gzzip${artifactId}-${version}checkstyle.xmlLICENSE.txtNOTICE.txtpom.xmlRELEASE-NOTES.txtsrctarget*.jar
================================================
FILE: src/main/checkstyle/checkstyle.xml
================================================
================================================
FILE: src/main/java/module-info.java
================================================
/*
* Copyright 2001-present Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* Joda-Beans is a small framework that adds properties to Java, greatly enhancing JavaBeans.
*
* The key concept is to allow each property on a bean to be accessed as an object in its own right.
* This provides the hook for other technologies to build on, such as serialization, mapping,
* expression languages and validation.
*/
module org.joda.beans {
// dependency on Joda-Convert
requires transitive org.joda.convert;
// dependency on XML parser
requires java.xml;
// optional dependency on Guava
requires static com.google.common;
// optional dependency on Joda-Collect
requires static org.joda.collect;
// export all packages
exports org.joda.beans;
exports org.joda.beans.gen;
exports org.joda.beans.impl;
exports org.joda.beans.impl.direct;
exports org.joda.beans.impl.flexi;
exports org.joda.beans.impl.light;
exports org.joda.beans.impl.map;
exports org.joda.beans.impl.reflection;
exports org.joda.beans.ser;
exports org.joda.beans.ser.bin;
exports org.joda.beans.ser.json;
exports org.joda.beans.ser.map;
exports org.joda.beans.ser.xml;
exports org.joda.beans.test;
}
================================================
FILE: src/main/java/org/joda/beans/Bean.java
================================================
/*
* Copyright 2001-present Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.joda.beans;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* A bean consisting of a set of properties.
*
* The implementation may be any class, but is typically a standard JavaBean
* with get/set methods. Alternate implementations might store the properties
* in another data structure such as a map.
*/
public interface Bean {
/**
* Gets the meta-bean representing the parts of the bean that are
* common across all instances, such as the set of meta-properties.
*
* The meta-bean can be thought of as the equivalent of {@link Class} but for beans.
*
* @return the meta-bean, not null
*/
public abstract MetaBean metaBean();
/**
* Gets a property by name.
*
* Each bean consists of a known set of properties.
* This method checks whether there is a property with the specified name.
*
* The base interface throws an exception if the name is not recognised.
* By contrast, the {@code DynamicBean} interface creates the property on demand.
*
* @param the property type, optional, enabling auto-casting
* @param propertyName the property name to retrieve, not null
* @return the property, not null
* @throws NoSuchElementException if the property name is invalid
*/
public default Property property(String propertyName) {
return metaBean().metaProperty(propertyName).createProperty(this);
}
/**
* Gets the set of property names.
*
* Each bean consists of a known set of properties.
* This method returns the known property names.
*
* @return the unmodifiable set of property names, not null
*/
public default Set propertyNames() {
return metaBean().metaPropertyMap().keySet();
}
}
================================================
FILE: src/main/java/org/joda/beans/BeanBuilder.java
================================================
/*
* Copyright 2001-present Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.joda.beans;
/**
* A builder for a bean, providing a safe way to create it.
*
* This interface allows a bean to be created even if it is immutable.
*
* @param the type of the bean
*/
public interface BeanBuilder {
/**
* Gets the value of a single property previously added to the builder.
*
* @param propertyName the property name to query, not null
* @return the previously set value, null if none
* @throws RuntimeException thrown if the property name is invalid
*/
public abstract Object get(String propertyName);
/**
* Gets the value of a single property previously added to the builder.
*
* @param metaProperty the meta-property to query, not null
* @return the previously set value, null if none
* @throws RuntimeException thrown if the property is invalid
* @param
the type of the property.
*/
public abstract
P get(MetaProperty
metaProperty);
/**
* Sets the value of a single property into the builder.
*
* This will normally behave as per a {@code Map}, however it may not
* and as a general rule callers should only set each property once.
*
* @param propertyName the property name to set, not null
* @param value the property value, may be null
* @return {@code this}, for chaining, not null
* @throws RuntimeException optionally thrown if the property name is invalid
*/
public abstract BeanBuilder set(String propertyName, Object value);
/**
* Sets the value of a single property into the builder.
*
* This will normally behave as per a {@code Map}, however it may not
* and as a general rule callers should only set each property once.
*
* @param metaProperty the meta-property to set, not null
* @param value the property value, may be null
* @return {@code this}, for chaining, not null
* @throws RuntimeException optionally thrown if the property is invalid
*/
public abstract BeanBuilder set(MetaProperty> metaProperty, Object value);
/**
* Builds the bean from the state of the builder.
*
* Once this method has been called, the builder is in an invalid state.
* The effect of further method calls is undetermined.
*
* @return the created bean, not null
*/
public abstract T build();
}
================================================
FILE: src/main/java/org/joda/beans/BeanIterator.java
================================================
/*
* Copyright 2001-present Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.joda.beans;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Deque;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import org.joda.beans.ser.SerIteratorFactory;
/**
* An iterator over beans.
*/
final class BeanIterator implements Iterator {
/**
* The stack of beans.
*/
private final List stack = new ArrayList<>(32);
/**
* Creates an instance.
*
* @param root the bean to iterate over
*/
BeanIterator(Bean root) {
this.stack.add(root);
}
@Override
public boolean hasNext() {
return !stack.isEmpty();
}
@Override
public Bean next() {
if (!hasNext()) {
throw new NoSuchElementException("No more elements in the iterator");
}
// next bean to return is head of the stack
var currentBean = stack.remove(stack.size() - 1);
// temp used to reverse the order of child beans to match depth-first order
// alternative is to insert into stack at a fixed index (lots of array copying)
var temp = new ArrayDeque(32);
for (var mp : currentBean.metaBean().metaPropertyIterable()) {
findChildBeans(mp.get(currentBean), mp, currentBean.getClass(), temp);
}
stack.addAll(temp);
return currentBean;
}
// find child beans, including those in collections
private void findChildBeans(Object obj, MetaProperty> mp, Class> beanClass, Deque temp) {
if (obj != null) {
if (obj instanceof Bean bean) {
temp.addFirst(bean);
} else {
var it = SerIteratorFactory.INSTANCE.create(obj, mp, beanClass);
if (it != null) {
while (it.hasNext()) {
it.next();
findChildBeans(it.key(), mp, Object.class, temp);
findChildBeans(it.value(), mp, Object.class, temp);
findChildBeans(it.column(), mp, Object.class, temp);
}
}
}
}
}
@Override
public void remove() {
throw new UnsupportedOperationException("BeanIterator does not support remove()");
}
}
================================================
FILE: src/main/java/org/joda/beans/DynamicBean.java
================================================
/*
* Copyright 2001-present Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.joda.beans;
/**
* A dynamic bean that allows properties to be added and removed.
*
* A JavaBean is defined at compile-time and cannot have additional properties added.
* Instances of this interface allow additional properties to be added and removed
* probably by wrapping a map
*/
public interface DynamicBean extends Bean {
/**
* Gets the meta-bean representing the parts of the bean that are
* common across all instances, such as the set of meta-properties.
*
* @return the meta-bean, not null
*/
@Override
public abstract DynamicMetaBean metaBean();
/**
* Gets a property by name.
*
* This will not throw an exception if the property name does not exist.
* Whether a property is immediately created or not is implementation dependent.
*
* @param the property type, optional, enabling auto-casting
* @param propertyName the property name to retrieve, not null
* @return the property, not null
*/
@Override
public abstract Property property(String propertyName);
/**
* Adds a property to those allowed to be stored in the bean.
*
* Some implementations will automatically add properties, in which case this
* method will have no effect.
*
* @param propertyName the property name to check, not empty, not null
* @param propertyType the property type, not null
*/
public abstract void propertyDefine(String propertyName, Class> propertyType);
/**
* Removes a property by name.
*
* @param propertyName the property name to remove, null ignored
*/
public abstract void propertyRemove(String propertyName);
}
================================================
FILE: src/main/java/org/joda/beans/DynamicMetaBean.java
================================================
/*
* Copyright 2001-present Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.joda.beans;
/**
* A dynamic meta-bean which works with {@code DynamicBean}.
*
* A dynamic bean can have properties added or removed at any time.
* As such, there is a different meta-bean for each dynamic bean.
* The meta-bean allows meta-properties to be created on demand.
*/
public interface DynamicMetaBean extends MetaBean {
/**
* Creates a bean builder that can be used to create an instance of this bean.
*
* All properties added to the builder will be created and appear in the result.
*
* @return the bean builder, not null
* @throws UnsupportedOperationException if the bean cannot be created
*/
@Override
public abstract BeanBuilder extends DynamicBean> builder();
/**
* Get the type of the bean represented as a {@code Class}.
*
* @return the type of the bean, not null
*/
@Override
public abstract Class extends DynamicBean> beanType();
/**
* Gets a meta-property by name.
*
* This will not throw an exception if the meta-property name does not exist.
* Whether a meta-property is immediately created or not is implementation dependent.
*
* @param the property type, optional, enabling auto-casting
* @param propertyName the property name to retrieve, not null
* @return the meta property, not null
*/
@Override
public abstract MetaProperty metaProperty(String propertyName);
//-----------------------------------------------------------------------
/**
* Defines a property for the bean.
*
* Some implementations will automatically add properties, in which case this
* method will have no effect.
*
* @param propertyName the property name to check, not empty, not null
* @param propertyType the property type, not null
*/
public abstract void metaPropertyDefine(String propertyName, Class> propertyType);
/**
* Removes a property by name.
*
* @param propertyName the property name to remove, null ignored
*/
public abstract void metaPropertyRemove(String propertyName);
}
================================================
FILE: src/main/java/org/joda/beans/ImmutableBean.java
================================================
/*
* Copyright 2001-present Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.joda.beans;
/**
* An immutable bean consisting of a set of properties.
*
* This marker interface allows immutable beans to be identified.
*/
public interface ImmutableBean extends Bean {
}
================================================
FILE: src/main/java/org/joda/beans/JodaBeanUtils.java
================================================
/*
* Copyright 2001-present Stephen Colebourne
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.joda.beans;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
import java.util.TreeSet;
import java.util.function.Function;
import org.joda.beans.impl.direct.DirectBean;
import org.joda.beans.impl.flexi.FlexiBean;
import org.joda.collect.grid.DenseGrid;
import org.joda.collect.grid.Grid;
import org.joda.collect.grid.ImmutableGrid;
import org.joda.collect.grid.SparseGrid;
import org.joda.convert.StringConvert;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.HashBiMap;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableMultimap;
import com.google.common.collect.ImmutableMultiset;
import com.google.common.collect.ImmutableTable;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.LinkedHashMultiset;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multiset;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.SortedMultiset;
import com.google.common.collect.Table;
import com.google.common.collect.TreeMultiset;
/**
* A set of utilities to assist when working with beans and properties.
*/
public final class JodaBeanUtils {
/**
* The cache of meta-beans.
*/
private static final StringConvert converter = new StringConvert();
/**
* Restricted constructor.
*/
private JodaBeanUtils() {
}
//-----------------------------------------------------------------------
/**
* Gets the standard string format converter.
*
* This returns a singleton that may be mutated (holds a concurrent map).
* New conversions should be registered at program startup.
*
* @return the standard string converter, not null
*/
public static StringConvert stringConverter() {
return converter;
}
//-----------------------------------------------------------------------
/**
* Checks if two objects are equal handling null.
*
* @param obj1 the first object, may be null
* @param obj2 the second object, may be null
* @return true if equal
*/
public static boolean equal(Object obj1, Object obj2) {
if (obj1 == obj2) {
return true;
}
if (obj1 == null || obj2 == null) {
return false;
}
if (obj1.getClass().isArray()) {
return equalsArray(obj1, obj2);
}
// this does not handle arrays embedded in objects, such as in lists/maps,
// but you shouldn't use arrays like that, should you?
return obj1.equals(obj2);
}
// extracted from equal(Object,Object) to aid hotspot inlining
private static boolean equalsArray(Object obj1, Object obj2) {
if (obj1.getClass() != obj2.getClass()) {
return false;
}
return switch (obj1) {
case Object[] objects -> Arrays.deepEquals(objects, (Object[]) obj2);
case int[] ints -> Arrays.equals(ints, (int[]) obj2);
case long[] longs -> Arrays.equals(longs, (long[]) obj2);
case byte[] bytes -> Arrays.equals(bytes, (byte[]) obj2);
case double[] doubles -> Arrays.equals(doubles, (double[]) obj2);
case float[] floats -> Arrays.equals(floats, (float[]) obj2);
case char[] chars -> Arrays.equals(chars, (char[]) obj2);
case short[] shorts -> Arrays.equals(shorts, (short[]) obj2);
case boolean[] booleans -> Arrays.equals(booleans, (boolean[]) obj2);
default -> false; // unreachable?
};
}
/**
* Checks if two floats are equal based on identity.
*
* This performs the same check as {@link Float#equals(Object)}.
*
* @param val1 the first value, may be null
* @param val2 the second value, may be null
* @return true if equal
*/
public static boolean equal(float val1, float val2) {
return Float.floatToIntBits(val1) == Float.floatToIntBits(val2);
}
/**
* Checks if two floats are equal within the specified tolerance.
*
* Two NaN values are equal. Positive and negative infinity are only equal with themselves.
* Otherwise, the difference between the values is compared to the tolerance.
*
* @param val1 the first value, may be null
* @param val2 the second value, may be null
* @param tolerance the tolerance used to compare equal
* @return true if equal
*/
public static boolean equalWithTolerance(float val1, float val2, double tolerance) {
return (Float.floatToIntBits(val1) == Float.floatToIntBits(val2)) || Math.abs(val1 - val2) <= tolerance;
}
/**
* Checks if two doubles are equal based on identity.
*
* This performs the same check as {@link Double#equals(Object)}.
*
* @param val1 the first value, may be null
* @param val2 the second value, may be null
* @return true if equal
*/
public static boolean equal(double val1, double val2) {
return Double.doubleToLongBits(val1) == Double.doubleToLongBits(val2);
}
/**
* Checks if two doubles are equal within the specified tolerance.
*
* Two NaN values are equal. Positive and negative infinity are only equal with themselves.
* Otherwise, the difference between the values is compared to the tolerance.
* The tolerance is expected to be a finite value, not NaN or infinity.
*
* @param val1 the first value, may be null
* @param val2 the second value, may be null
* @param tolerance the tolerance used to compare equal
* @return true if equal
*/
public static boolean equalWithTolerance(double val1, double val2, double tolerance) {
return (Double.doubleToLongBits(val1) == Double.doubleToLongBits(val2)) || Math.abs(val1 - val2) <= tolerance;
}
/**
* Returns a hash code for an object handling null.
*
* @param obj the object, may be null
* @return the hash code
*/
public static int hashCode(Object obj) {
if (obj == null) {
return 0;
}
if (obj.getClass().isArray()) {
return hashCodeArray(obj);
}
return obj.hashCode();
}
// extracted from hashCode(Object) to aid hotspot inlining
private static int hashCodeArray(Object obj) {
return switch (obj) {
case Object[] objects -> Arrays.deepHashCode(objects);
case int[] ints -> Arrays.hashCode(ints);
case long[] longs -> Arrays.hashCode(longs);
case byte[] bytes -> Arrays.hashCode(bytes);
case double[] doubles -> Arrays.hashCode(doubles);
case float[] floats -> Arrays.hashCode(floats);
case char[] chars -> Arrays.hashCode(chars);
case short[] shorts -> Arrays.hashCode(shorts);
case boolean[] booleans -> Arrays.hashCode(booleans);
default -> obj.hashCode(); // unreachable?
};
}
/**
* Returns a hash code for a {@code boolean}.
*
* @param value the value to convert to a hash code
* @return the hash code
*/
public static int hashCode(boolean value) {
return value ? 1231 : 1237;
}
/**
* Returns a hash code for an {@code int}.
*
* @param value the value to convert to a hash code
* @return the hash code
*/
public static int hashCode(int value) {
return value;
}
/**
* Returns a hash code for a {@code long}.
*
* @param value the value to convert to a hash code
* @return the hash code
*/
public static int hashCode(long value) {
return Long.hashCode(value);
}
/**
* Returns a hash code for a {@code float}.
*
* @param value the value to convert to a hash code
* @return the hash code
*/
public static int hashCode(float value) {
return Float.hashCode(value);
}
/**
* Returns a hash code for a {@code double}.
*
* @param value the value to convert to a hash code
* @return the hash code
*/
public static int hashCode(double value) {
return Double.hashCode(value);
}
//-----------------------------------------------------------------------
/**
* Returns the {@code toString} value handling arrays.
*
* @param obj the object, may be null
* @return the string, not null
*/
public static String toString(Object obj) {
if (obj == null) {
return "null";
}
if (obj.getClass().isArray()) {
return toStringArray(obj);
}
return obj.toString();
}
// extracted from toString(Object) to aid hotspot inlining
private static String toStringArray(Object obj) {
return switch (obj) {
case Object[] objects -> Arrays.deepToString(objects);
case int[] ints -> Arrays.toString(ints);
case long[] longs -> Arrays.toString(longs);
case byte[] bytes -> Arrays.toString(bytes);
case double[] doubles -> Arrays.toString(doubles);
case float[] floats -> Arrays.toString(floats);
case char[] chars -> Arrays.toString(chars);
case short[] shorts -> Arrays.toString(shorts);
case boolean[] booleans -> Arrays.toString(booleans);
default -> obj.toString(); // unreachable?
};
}
//-----------------------------------------------------------------------
/**
* Checks if the two beans have the same set of properties.
*
* This comparison checks that both beans have the same set of property names
* and that the value of each property name is also equal.
* It does not check the bean type, thus a {@link FlexiBean} may be equal
* to a {@link DirectBean}.
*
* This comparison is usable with the {@link #propertiesHashCode} method.
* The result is the same as that if each bean was converted to a {@code Map}
* from name to value.
*
* @param bean1 the first bean to compare, not null
* @param bean2 the second bean to compare, not null
* @return true if equal
*/
public static boolean propertiesEqual(Bean bean1, Bean bean2) {
var names = bean1.propertyNames();
if (!names.equals(bean2.propertyNames())) {
return false;
}
for (var name : names) {
var value1 = bean1.property(name).get();
var value2 = bean2.property(name).get();
if (!equal(value1, value2)) {
return false;
}
}
return true;
}
/**
* Returns a hash code based on the set of properties on a bean.
*
* This hash code is usable with the {@link #propertiesEqual} method.
* The result is the same as that if each bean was converted to a {@code Map}
* from name to value.
*
* @param bean the bean to generate a hash code for, not null
* @return the hash code
*/
public static int propertiesHashCode(Bean bean) {
var hash = 7;
var names = bean.propertyNames();
for (var name : names) {
var value = bean.property(name).get();
hash += hashCode(value);
}
return hash;
}
/**
* Returns a string describing the set of properties on a bean.
*
* The result is the same as that if the bean was converted to a {@code Map}
* from name to value.
*
* @param bean the bean to generate a string for, not null
* @param prefix the prefix to use, null ignored
* @return the string form of the bean, not null
*/
public static String propertiesToString(Bean bean, String prefix) {
if (prefix == null) {
return propertiesToString(bean, "");
}
var names = bean.propertyNames();
var buf = new StringBuilder((names.size()) * 32 + prefix.length()).append(prefix);
buf.append('{');
if (!names.isEmpty()) {
for (var name : names) {
var value = bean.property(name).get();
buf.append(name).append('=').append(value).append(',').append(' ');
}
buf.setLength(buf.length() - 2);
}
buf.append('}');
return buf.toString();
}
/**
* Flattens a bean to a {@code Map}.
*
* The returned map will contain all the properties from the bean with their actual values.
*
* @param bean the bean to generate a string for, not null
* @return the bean as a map, not null
*/
public static Map flatten(Bean bean) {
var propertyMap = bean.metaBean().metaPropertyMap();
var map = new LinkedHashMap(propertyMap.size());
for (var entry : propertyMap.entrySet()) {
map.put(entry.getKey(), entry.getValue().get(bean));
}
return Collections.unmodifiableMap(map);
}
//-----------------------------------------------------------------------
/**
* Copies properties from a bean to a different bean type.
*
* This copies each non-null property value from the source bean to the destination builder
* provided that the destination builder supports the property name and the type is compatible.
*
* @param the type of the bean to create
* @param sourceBean the bean to copy from, not null
* @param destType the type of the destination bean, not null
* @return the copied bean as a builder
* @throws RuntimeException if unable to copy a property
*/
public static BeanBuilder copy(Bean sourceBean, Class destType) {
var destMeta = MetaBean.of(destType);
@SuppressWarnings("unchecked")
var destBuilder = (BeanBuilder) destMeta.builder();
return copyInto(sourceBean, destMeta, destBuilder);
}
/**
* Copies properties from a bean to a builder, which may be for a different type.
*
* This copies each non-null property value from the source bean to the destination builder
* provided that the destination builder supports the property name and the type is compatible.
*
* @param the type of the bean to create
* @param sourceBean the bean to copy from, not null
* @param destMeta the meta bean of the destination, not null
* @param destBuilder the builder to populate, not null
* @return the updated builder
* @throws RuntimeException if unable to copy a property
*/
public static BeanBuilder copyInto(Bean sourceBean, MetaBean destMeta, BeanBuilder destBuilder) {
var sourceMeta = sourceBean.metaBean();
for (var sourceProp : sourceMeta.metaPropertyIterable()) {
if (destMeta.metaPropertyExists(sourceProp.name())) {
var destProp = destMeta.metaProperty(sourceProp.name());
if (destProp.propertyType().isAssignableFrom(sourceProp.propertyType())) {
var sourceValue = sourceProp.get(sourceBean);
if (sourceValue != null) {
destBuilder.set(destProp, sourceValue);
}
}
}
}
return destBuilder;
}
//-----------------------------------------------------------------------
/**
* Deep clones an array.
*
* This performs a deep clone and handles multi-dimensional arrays.
* There is no protection against cycles in the object graph beyond {@code StackOverflowError}.
*
* Unfortunately, primitive arrays don't play nicely with generics, thus callers must cast the result.
*
* @param original the original array to clone, null returns null
* @return the cloned array, null if null input
* @throws IllegalArgumentException if the original object is not an array
* @since 2.12.0
*/
@SuppressWarnings("unchecked")
public static Object cloneArray(Object original) {
if (original == null) {
return null;
}
int len = Array.getLength(original);
Class> arrayType = original.getClass().getComponentType();
Object copy = Array.newInstance(arrayType, len);
for (int i = 0; i < len; i++) {
Array.set(copy, i, Cloner.INSTANCE.clone(Array.get(original, i)));
}
return copy;
}
/**
* Deep clones a bean, without cloning an {@code ImmutableBean}.
*
* This performs a deep clone. There is no protection against cycles in
* the object graph beyond {@code StackOverflowError}.
*
* @param the type of the bean
* @param original the original bean to clone, null returns null
* @return the cloned bean, null if null input
*/
public static T clone(T original) {
if (original == null || original instanceof ImmutableBean) {
return original;
}
return cloneAlways(original);
}
/**
* Deep clones a bean always.
*
* This performs a deep clone. There is no protection against cycles in
* the object graph beyond {@code StackOverflowError}.
* This differs from {@link #clone()} in that immutable beans are also cloned.
*
* @param the type of the bean
* @param original the original bean to clone, not null
* @return the cloned bean, not null
*/
public static T cloneAlways(T original) {
@SuppressWarnings("unchecked")
var builder = (BeanBuilder) original.metaBean().builder();
for (var mp : original.metaBean().metaPropertyIterable()) {
if (mp.style().isBuildable()) {
var value = mp.get(original);
builder.set(mp.name(), Cloner.INSTANCE.clone(value));
}
}
return builder.build();
}
//-----------------------------------------------------------------------
/**
* Checks if the value is not null, throwing an exception if it is.
*
* @param value the value to check, may be null
* @param propertyName the property name, should not be null
* @throws IllegalArgumentException if the value is null
*/
public static void notNull(Object value, String propertyName) {
if (value == null) {
throw new IllegalArgumentException(notNullMsg(propertyName));
}
}
// extracted from notNull(Object,String) to aid hotspot inlining
private static String notNullMsg(String propertyName) {
return "Argument '" + propertyName + "' must not be null";
}
/**
* Checks if the value is not blank, throwing an exception if it is.
*
* Validate that the specified argument is not null and has at least one non-whitespace character.
*
* @param value the value to check, may be null
* @param propertyName the property name, should not be null
* @throws IllegalArgumentException if the value is null or empty
*/
public static void notBlank(String value, String propertyName) {
if (value == null || value.isBlank()) {
throw new IllegalArgumentException(notEmpty(propertyName));
}
}
/**
* Checks if the value is not empty, throwing an exception if it is.
*
* @param value the value to check, may be null
* @param propertyName the property name, should not be null
* @throws IllegalArgumentException if the value is null or empty
*/
public static void notEmpty(String value, String propertyName) {
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException(notEmpty(propertyName));
}
}
// extracted from notEmpty(?,String) to aid hotspot inlining
private static String notEmpty(String propertyName) {
return "Argument '" + propertyName + "' must not be empty";
}
/**
* Checks if the collection value is not empty, throwing an exception if it is.
*
* @param value the value to check, may be null
* @param propertyName the property name, should not be null
* @throws IllegalArgumentException if the value is null or empty
*/
public static void notEmpty(Collection> value, String propertyName) {
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException(notEmpty(propertyName));
}
}
/**
* Checks if the map value is not empty, throwing an exception if it is.
*
* @param value the value to check, may be null
* @param propertyName the property name, should not be null
* @throws IllegalArgumentException if the value is null or empty
*/
public static void notEmpty(Map, ?> value, String propertyName) {
if (value == null || value.isEmpty()) {
throw new IllegalArgumentException(notEmpty(propertyName));
}
}
//-----------------------------------------------------------------------
/**
* Extracts the collection content type as a {@code Class} from a property.
*
* This method allows the resolution of generics in certain cases.
*
* @param prop the property to examine, not null
* @return the collection content type, null if unable to determine or type has no generic parameters
*/
public static Class> collectionType(Property> prop) {
return collectionType(prop.metaProperty(), prop.bean().getClass());
}
/**
* Extracts the collection content type as a {@code Class} from a meta-property.
*
* The target type is the type of the object, not the declaring type of the meta-property.
*
* @param prop the property to examine, not null
* @param contextClass the context class to evaluate against, not null
* @return the collection content type, null if unable to determine or type has no generic parameters
*/
public static Class> collectionType(MetaProperty> prop, Class> contextClass) {
return extractTypeClass(prop, contextClass, 1, 0);
}
/**
* Extracts the map value type generic type parameters as a {@code Class} from a meta-property.
*
* The target type is the type of the object, not the declaring type of the meta-property.
*
* This is used when the collection generic parameter is a map or collection.
*
* @param prop the property to examine, not null
* @param contextClass the context class to evaluate against, not null
* @return the collection content type generic parameters, empty if unable to determine, no nulls
*/
public static List> collectionTypeTypes(MetaProperty> prop, Class> contextClass) {
var type = extractType(prop, contextClass, 1, 0);
return extractTypeClasses(type, contextClass);
}
/**
* Extracts the map key type as a {@code Class} from a meta-property.
*
* @param prop the property to examine, not null
* @return the map key type, null if unable to determine or type has no generic parameters
*/
public static Class> mapKeyType(Property> prop) {
return mapKeyType(prop.metaProperty(), prop.bean().getClass());
}
/**
* Extracts the map key type as a {@code Class} from a meta-property.
*
* The target type is the type of the object, not the declaring type of the meta-property.
*
* @param prop the property to examine, not null
* @param contextClass the context class to evaluate against, not null
* @return the map key type, null if unable to determine or type has no generic parameters
*/
public static Class> mapKeyType(MetaProperty> prop, Class> contextClass) {
return extractTypeClass(prop, contextClass, 2, 0);
}
/**
* Extracts the map value type as a {@code Class} from a meta-property.
*
* @param prop the property to examine, not null
* @return the map value type, null if unable to determine or type has no generic parameters
*/
public static Class> mapValueType(Property> prop) {
return mapValueType(prop.metaProperty(), prop.bean().getClass());
}
/**
* Extracts the map value type as a {@code Class} from a meta-property.
*
* The target type is the type of the object, not the declaring type of the meta-property.
*
* @param prop the property to examine, not null
* @param contextClass the context class to evaluate against, not null
* @return the map value type, null if unable to determine or type has no generic parameters
*/
public static Class> mapValueType(MetaProperty> prop, Class> contextClass) {
return extractTypeClass(prop, contextClass, 2, 1);
}
/**
* Extracts the map value type generic type parameters as a {@code Class} from a meta-property.
*
* The target type is the type of the object, not the declaring type of the meta-property.
*
* This is used when the map value generic parameter is a map or collection.
*
* @param prop the property to examine, not null
* @param contextClass the context class to evaluate against, not null
* @return the map value type generic parameters, empty if unable to determine, no nulls
*/
public static List> mapValueTypeTypes(MetaProperty> prop, Class> contextClass) {
var type = extractType(prop, contextClass, 2, 1);
return extractTypeClasses(type, contextClass);
}
/**
* Low-level method to extract generic type information.
*
* @param prop the property to examine, not null
* @param contextClass the context class to evaluate against, not null
* @param size the number of generic parameters expected
* @param index the index of the generic parameter
* @return the type, null if unable to determine or type has no generic parameters
*/
public static Class> extractTypeClass(MetaProperty> prop, Class> contextClass, int size, int index) {
return eraseToClass(extractType(prop, contextClass, size, index));
}
private static Type extractType(MetaProperty> prop, Class> contextClass, int size, int index) {
var genType = prop.propertyGenericType();
if (genType instanceof ParameterizedType pt) {
var types = pt.getActualTypeArguments();
if (types.length == size) {
var type = types[index];
if (type instanceof WildcardType wtype) {
if (wtype.getLowerBounds().length == 0 && wtype.getUpperBounds().length > 0) {
type = wtype.getUpperBounds()[0];
}
}
if (type instanceof TypeVariable> tvar) {
type = resolveGenerics(tvar, contextClass);
}
return type;
}
}
return null;
}
private static List> extractTypeClasses(Type type, Class> contextClass) {
var result = new ArrayList>();
if (type != null) {
if (type instanceof ParameterizedType pt) {
var actualTypes = pt.getActualTypeArguments();
for (var actualType : actualTypes) {
if (actualType instanceof TypeVariable> tvar) {
actualType = resolveGenerics(tvar, contextClass);
}
var cls = eraseToClass(actualType);
result.add(cls != null ? cls : Object.class);
}
}
}
return result;
}
// cache the type variable lookup by Class
private static final ClassValue