Skip to content

Commit

Permalink
Merge pull request #351 from klum-dsl/feature/309-copyfrom-strategies
Browse files Browse the repository at this point in the history
Copy Strategies
  • Loading branch information
pauxus authored Jan 14, 2025
2 parents faf0809 + c0b8ba6 commit f62fce8
Show file tree
Hide file tree
Showing 29 changed files with 2,068 additions and 333 deletions.
1 change: 1 addition & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
- Ower fields can be filled with the actual root of the model. This works even if no explicit owner field is present (see [Root Owner](https://github.com/klum-dsl/klum-ast/wiki/Basics#root-owners))
- Owner objects can be converted before handing them to owner fields or methods (see [Owner Converters](https://github.com/klum-dsl/klum-ast/wiki/Basics#owner-converters) and [#189](https://github.com/klum-dsl/klum-ast/issues/189))
- New `@Role` annotation to infer the name of the owner field containing an object (see [Role fields](https://github.com/klum-dsl/klum-ast/wiki/Layer3#role-fields) and [#86](https://github.com/klum-dsl/klum-ast/issues/86))
- Overwrite strategies for `copyFrom` and templates (see [Copy Strategies](https://github.com/klum-dsl/klum-ast/wiki/Copy-Strategies) and [#309](https://github.com/klum-dsl/klum-ast/issues/309))

## Improvements
- Creator classes also support methods creating multiple instances at once (see [#319](https://github.com/klum-dsl/klum-ast/issues/319))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
*/
@Target(ElementType.ANNOTATION_TYPE)
@Retention(RetentionPolicy.RUNTIME)
@KlumCastValidator("com.blackbuild.groovy.configdsl.transform.ast.mutators.WriteAccessMethodCheck")
@KlumCastValidator(validForTargets = ElementType.METHOD, value = "com.blackbuild.groovy.configdsl.transform.ast.mutators.WriteAccessMethodCheck")
@Documented
public @interface WriteAccess {

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 Stephan Pauxberger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.blackbuild.klum.ast.util.copy;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Default overwrite strategy. Merges single values (or overwrite non DSL single values), adds collections and merges maps.
*/
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
@Overwrite(
singles = @Overwrite.Single(OverwriteStrategy.Single.MERGE),
collections = @Overwrite.Collection(OverwriteStrategy.Collection.ADD),
maps = @Overwrite.Map(OverwriteStrategy.Map.MERGE_VALUES)
)
public @interface DefaultOverwrite {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 Stephan Pauxberger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.blackbuild.klum.ast.util.copy;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Overwrite strategy that completely replaces the target`s fields with those of the source, only ignoring null values.
*/
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
@Overwrite(
singles = @Overwrite.Single(OverwriteStrategy.Single.REPLACE),
collections = @Overwrite.Collection(OverwriteStrategy.Collection.ALWAYS_REPLACE),
maps = @Overwrite.Map(OverwriteStrategy.Map.FULL_REPLACE)
)
public @interface FullReplaceOverwrite {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 Stephan Pauxberger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.blackbuild.klum.ast.util.copy;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Helm like overwrite strategy. Merges single values (or overwrite non DSL single values), replaces collections even
* if copy source is empty and merges maps.
*/
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
@Overwrite(
singles = @Overwrite.Single(OverwriteStrategy.Single.MERGE),
collections = @Overwrite.Collection(OverwriteStrategy.Collection.ALWAYS_REPLACE),
maps = @Overwrite.Map(OverwriteStrategy.Map.MERGE_VALUES)
)
public @interface HelmOverwrite {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 Stephan Pauxberger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.blackbuild.klum.ast.util.copy;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Overwrite strategy of KlumAST 1.x. Merges single values (or overwrite non DSL single values), replaces collections even
* if copy source is empty and merges maps.
*/
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
@Overwrite(
singles = @Overwrite.Single(OverwriteStrategy.Single.MERGE),
collections = @Overwrite.Collection(OverwriteStrategy.Collection.ALWAYS_REPLACE),
maps = @Overwrite.Map(OverwriteStrategy.Map.FULL_REPLACE)
)
public @interface LegacyOverwrite {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 Stephan Pauxberger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.blackbuild.klum.ast.util.copy;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Overwrite strategy that only modifies empty/null fields of the target.
*/
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
@Overwrite(
singles = @Overwrite.Single(OverwriteStrategy.Single.SET_IF_NULL),
collections = @Overwrite.Collection(OverwriteStrategy.Collection.SET_IF_EMPTY),
maps = @Overwrite.Map(OverwriteStrategy.Map.SET_IF_EMPTY)
)
public @interface LenientOverwrite {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 Stephan Pauxberger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.blackbuild.klum.ast.util.copy;

import com.blackbuild.groovy.configdsl.transform.cast.NeedsDSLClass;
import com.blackbuild.klum.cast.KlumCastValidated;
import com.blackbuild.klum.cast.KlumCastValidator;
import com.blackbuild.klum.cast.checks.NeedsOneOf;
import com.blackbuild.klum.cast.checks.NeedsType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Handles how values are copied from one object to another.
*/
@Target({ElementType.FIELD, ElementType.TYPE, ElementType.PACKAGE})
@Retention(RetentionPolicy.RUNTIME)
@KlumCastValidated
@NeedsDSLClass
@NeedsOneOf(value = {"singles", "collections", "maps"})
public @interface Overwrite {

Overwrite.Single singles() default @Overwrite.Single(OverwriteStrategy.Single.INHERIT);
Overwrite.Collection collections() default @Overwrite.Collection(OverwriteStrategy.Collection.INHERIT);
Overwrite.Map maps() default @Overwrite.Map(OverwriteStrategy.Map.INHERIT);

@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@KlumCastValidated
@NeedsDSLClass
@KlumCastValidator("com.blackbuild.klum.ast.validation.OverwriteSingleCheck")
@interface Single {
OverwriteStrategy.Single value();
}

@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@KlumCastValidated
@NeedsDSLClass
@NeedsType(java.util.Collection.class)
@interface Collection {
OverwriteStrategy.Collection value();
}

@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@KlumCastValidated
@NeedsDSLClass
@NeedsType(java.util.Map.class)
@KlumCastValidator("com.blackbuild.klum.ast.validation.OverwriteMapCheck")
@interface Map {
OverwriteStrategy.Map value();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2015-2024 Stephan Pauxberger
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
package com.blackbuild.klum.ast.util.copy;

/**
* Defines the various strategies for different targets. Note that the collection and map strategies are combined
* with dsl or basic object, depending on the element type
*/
public interface OverwriteStrategy {

/**
* Defines the strategy for a single dsl object.
*/
enum Single {
/** No explicit overwrite strategy is set. */
INHERIT,
/** The object is fully replaced. */
REPLACE,
/** The object is replaced even if the copy source is null. */
ALWAYS_REPLACE,
/** The object is set only when there was no previous value. */
SET_IF_NULL,
/** The object is merged with the existing object. */
MERGE
}

/**
* Defines the strategy for a collection.
*/
enum Collection {
/** No explicit overwrite strategy is set. */
INHERIT,
/**
* The members of the copy source are added to the target collection. Potential item replacements are handled
* by the target collection (like {@link java.util.Set})
*/
ADD,
/** The collection is fully replaced if the replacement is not empty. */
REPLACE,
/** The collection is fully replaced only if target has now elements. */
SET_IF_EMPTY,
/** The map is replaced even if the copy source is empty. */
ALWAYS_REPLACE,
}

/**
* Defines the strategy for a map.
*/
enum Map {
/** No explicit overwrite strategy is set. */
INHERIT,
/** The map is fully replaced if the replacement is not empty. */
FULL_REPLACE,
/** The map is replaced even if the copy source is empty. */
ALWAYS_REPLACE,
/** The map is replaced only if the target map is empty. */
SET_IF_EMPTY,
/** The members of the copy source are added to the target map. Members with the same keys are replaced. */
MERGE_KEYS,
/** The members of the copy source are added to the target map. Members with the same keys are merged. Only valid for DSL elements. */
MERGE_VALUES,
/** The members of the copy source are added to the target map. Members with the existing keys are ignored. */
ADD_MISSING
}
}
Loading

0 comments on commit f62fce8

Please sign in to comment.