This is an automated email from the ASF dual-hosted git repository.
tkobayas pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-kie.git
The following commit(s) were added to refs/heads/main by this push:
new 78ae3a02c05 [incubator-kie#7213] Consolidate type annotation
processing into TypeDeclarationFactory (#7216)
78ae3a02c05 is described below
commit 78ae3a02c0511e0ba67a789403679d4027b499ea
Author: Toshiya Kobayashi <[email protected]>
AuthorDate: Fri Oct 30 09:31:38 2026 +0900
[incubator-kie#7213] Consolidate type annotation processing into
TypeDeclarationFactory (#7216)
Annotation merging for type declarations was spread across three places,
causing @Role and @PropertyChangeSupport to be processed multiple times.
- Build a single merged Annotated (DRL + Java fallback) in
processAnnotations() and handle @Timestamp/@Duration attribute names
in processTypeAnnotations()
- Simplify wireFieldAccessors() to only wire extractors from values
already set on TypeDeclaration
- Stop re-reading @Duration/@Timestamp in exec-model TypeDeclarationUtil
- Apply processAnnotations() to the retained declaration in
redeclaration scenarios to preserve @classReactive, @expires, etc.
- Wrap annotation processing errors as TypeDeclarationError in
exec-model and impact analysis callers
- Pass configured PropertySpecificOption instead of hardcoding ALWAYS
Co-authored-by: Claude Opus 4.6 (1M context) <[email protected]>
---
.../java/org/drools/base/rule/TypeDeclaration.java | 19 ++++-
.../builder/impl/TypeDeclarationCache.java | 7 +-
.../builder/impl/TypeDeclarationConfigurator.java | 77 ++++--------------
.../builder/impl/TypeDeclarationFactory.java | 45 +++--------
.../parser/internal/ImpactModelBuilderImpl.java | 14 +++-
.../processors/DeclaredTypeCompilationPhase.java | 3 +-
.../processors/DeclaredTypeRegistrationPhase.java | 18 ++++-
.../tool/ExplicitCanonicalModelCompiler.java | 3 +-
.../model/codegen/execmodel/DeclaredTypesTest.java | 17 ++++
.../modelcompiler/util/TypeDeclarationUtil.java | 29 ++-----
.../compiler/compiler/TypeDeclarationTest.java | 91 ++++++++++++++++++++++
11 files changed, 193 insertions(+), 130 deletions(-)
diff --git
a/drools-base/src/main/java/org/drools/base/rule/TypeDeclaration.java
b/drools-base/src/main/java/org/drools/base/rule/TypeDeclaration.java
index d1448c742a9..d0aebe5f405 100644
--- a/drools-base/src/main/java/org/drools/base/rule/TypeDeclaration.java
+++ b/drools-base/src/main/java/org/drools/base/rule/TypeDeclaration.java
@@ -35,11 +35,13 @@ import org.drools.base.util.PropertyReactivityUtil;
import org.drools.base.util.TimeIntervalParser;
import org.drools.util.ClassUtils;
import org.kie.api.definition.type.ClassReactive;
+import org.kie.api.definition.type.Duration;
import org.kie.api.definition.type.Expires;
import org.kie.api.definition.type.Expires.Policy;
import org.kie.api.definition.type.PropertyChangeSupport;
import org.kie.api.definition.type.PropertyReactive;
import org.kie.api.definition.type.Role;
+import org.kie.api.definition.type.Timestamp;
import org.kie.api.io.Resource;
import org.kie.api.prototype.Prototype;
import org.kie.internal.builder.conf.PropertySpecificOption;
@@ -567,6 +569,8 @@ public class TypeDeclaration
configureExpirationOffset( type, annotated );
configurePropertyReactivity( type, annotated, propertySpecificOption );
configurePropertyChangeSupport( type, annotated );
+ configureTimestampAttribute( type, annotated );
+ configureDurationAttribute( type, annotated );
}
private static void configureRole( TypeDeclaration type, Annotated
annotated ) {
@@ -594,9 +598,22 @@ public class TypeDeclaration
}
private static void configurePropertyChangeSupport( TypeDeclaration type,
Annotated annotated ) {
- // only ever switch it on: a DRL declaration may already have made the
type dynamic
if ( annotated.hasAnnotation( PropertyChangeSupport.class ) ) {
type.setDynamic( true );
}
}
+
+ private static void configureTimestampAttribute( TypeDeclaration type,
Annotated annotated ) {
+ Timestamp timestamp = annotated.getTypedAnnotation(Timestamp.class);
+ if (timestamp != null) {
+ type.setTimestampAttribute( timestamp.value() );
+ }
+ }
+
+ private static void configureDurationAttribute( TypeDeclaration type,
Annotated annotated ) {
+ Duration duration = annotated.getTypedAnnotation(Duration.class);
+ if (duration != null) {
+ type.setDurationAttribute( duration.value() );
+ }
+ }
}
diff --git
a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationCache.java
b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationCache.java
index 2c83b241273..332c61bd501 100644
---
a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationCache.java
+++
b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationCache.java
@@ -31,10 +31,10 @@ import java.util.Set;
import org.drools.base.factmodel.ClassDefinition;
import org.drools.base.factmodel.FieldDefinition;
import org.drools.base.factmodel.traits.Thing;
-import org.drools.base.rule.Annotated;
import org.drools.base.rule.TypeDeclaration;
import org.drools.compiler.compiler.PackageRegistry;
import org.drools.compiler.compiler.TypeDeclarationError;
+import org.drools.drl.ast.descr.BaseDescr;
import org.drools.drl.ast.descr.PackageDescr;
import org.drools.util.ClassUtils;
import org.kie.api.definition.type.Position;
@@ -245,13 +245,12 @@ public class TypeDeclarationCache {
}
private TypeDeclaration createTypeDeclarationForBean(Class<?> cls) {
- Annotated annotated = new Annotated.ClassAdapter(cls);
- TypeDeclaration typeDeclaration =
TypeDeclaration.createTypeDeclarationForBean(cls, annotated,
context.getBuilderConfiguration().getOption(PropertySpecificOption.KEY));
+ TypeDeclaration typeDeclaration =
TypeDeclaration.createTypeDeclarationForBean(cls,
context.getBuilderConfiguration().getOption(PropertySpecificOption.KEY));
String namespace = ClassUtils.getPackage( cls );
PackageRegistry pkgRegistry = context.getOrCreatePackageRegistry( new
PackageDescr(namespace) );
- processMvelBasedAccessors(context, results, pkgRegistry, annotated,
typeDeclaration );
+ processMvelBasedAccessors(context, results, pkgRegistry, new
BaseDescr(), typeDeclaration );
return typeDeclaration;
}
diff --git
a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationConfigurator.java
b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationConfigurator.java
index 8b6b13061b1..d9b62ec6aaa 100644
---
a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationConfigurator.java
+++
b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationConfigurator.java
@@ -21,7 +21,6 @@ package org.drools.compiler.builder.impl;
import java.util.Map;
import org.drools.base.definitions.InternalKnowledgePackage;
-import org.drools.base.rule.Annotated;
import org.drools.base.rule.TypeDeclaration;
import org.drools.compiler.compiler.AnalysisResult;
import org.drools.compiler.compiler.BoundIdentifiers;
@@ -31,14 +30,8 @@ import org.drools.compiler.compiler.TypeDeclarationError;
import org.drools.compiler.rule.builder.PackageBuildContext;
import org.drools.drl.ast.descr.AbstractClassTypeDeclarationDescr;
import org.drools.drl.ast.descr.BaseDescr;
-import org.kie.api.definition.type.Duration;
-import org.kie.api.definition.type.Role;
-import org.kie.api.definition.type.Timestamp;
import org.kie.internal.builder.conf.PropertySpecificOption;
-import static org.drools.base.rule.TypeDeclaration.processTypeAnnotations;
-import static
org.drools.compiler.rule.builder.util.AnnotationFactory.toAnnotated;
-
public class TypeDeclarationConfigurator {
protected final TypeDeclarationContext context;
@@ -58,24 +51,8 @@ public class TypeDeclarationConfigurator {
if ( oldType == null ) {
pkgRegistry.getPackage().addTypeDeclaration( type );
} else {
- if (type.getRole() == Role.Type.EVENT) {
- oldType.setRole(Role.Type.EVENT);
- if ( type.getDurationAttribute() != null ) {
- oldType.setDurationAttribute(
type.getDurationAttribute() );
- oldType.setDurationExtractor(
type.getDurationExtractor() );
- }
- if ( type.getTimestampAttribute() != null ) {
- oldType.setTimestampAttribute(
type.getTimestampAttribute() );
- oldType.setTimestampExtractor(
type.getTimestampExtractor() );
- }
- if ( type.getExpirationOffset() >= 0 ) {
- oldType.setExpirationOffset(
type.getExpirationOffset() );
- oldType.setExpirationType( type.getExpirationPolicy()
);
- }
- }
- if (type.isPropertyReactive()) {
- oldType.setPropertyReactive(true);
- }
+ // the existing declaration is kept, so apply the annotations
of this redeclaration to it
+ TypeDeclarationFactory.processAnnotations( typeDescr, oldType,
context.getBuilderConfiguration().getOption( PropertySpecificOption.KEY ) );
}
}
}
@@ -99,62 +76,34 @@ public class TypeDeclarationConfigurator {
}
}
- // Annotations were pre-populated from Java and overridden by DRL in
processAnnotations().
- // The composite Annotated here re-applies them with DRL priority for
@Timestamp/@Duration
- // extractor wiring, which requires compiler infrastructure
unavailable in earlier steps.
- Annotated annotatedType = toAnnotated(typeDescr);
- if (type.getTypeClass() != null) {
- annotatedType = Annotated.withFallback(annotatedType, new
Annotated.ClassAdapter(type.getTypeClass()));
- }
- processMvelBasedAccessors(context, results, pkgRegistry,
annotatedType, type );
- processTypeAnnotations( type, annotatedType,
context.getBuilderConfiguration().getOption(PropertySpecificOption.KEY));
+ processMvelBasedAccessors(context, results, pkgRegistry, typeDescr,
type );
return true;
}
- static void processMvelBasedAccessors(TypeDeclarationContext context,
BuildResultCollector results, PackageRegistry pkgRegistry, Annotated annotated,
TypeDeclaration type ) {
- wireTimestampAccessor(context, results, annotated, type, pkgRegistry );
- wireDurationAccessor(context, results, annotated, type, pkgRegistry );
+ static void processMvelBasedAccessors(TypeDeclarationContext context,
BuildResultCollector results, PackageRegistry pkgRegistry, BaseDescr typeDescr,
TypeDeclaration type ) {
+ wireTimestampAccessor(context, results, typeDescr, type, pkgRegistry );
+ wireDurationAccessor(context, results, typeDescr, type, pkgRegistry );
}
- private static void wireTimestampAccessor(TypeDeclarationContext context,
BuildResultCollector resultCollector, Annotated annotated, TypeDeclaration
type, PackageRegistry pkgRegistry ) {
- Timestamp timestamp = annotated.getTypedAnnotation(Timestamp.class);
- if ( timestamp != null ) {
- BaseDescr typeDescr = annotated instanceof BaseDescr ? (
(BaseDescr) annotated ) : new BaseDescr();
- String timestampField;
- try {
- timestampField = timestamp.value();
- } catch (Exception e) {
- resultCollector.addBuilderResult(new
TypeDeclarationError(typeDescr, e.getMessage()));
- return;
- }
- type.setTimestampAttribute( timestampField );
+ private static void wireTimestampAccessor(TypeDeclarationContext context,
BuildResultCollector resultCollector, BaseDescr typeDescr, TypeDeclaration
type, PackageRegistry pkgRegistry ) {
+ String timestampField = type.getTimestampAttribute();
+ if ( timestampField != null ) {
InternalKnowledgePackage pkg = pkgRegistry.getPackage();
-
AnalysisResult results = getMvelAnalysisResult(context, typeDescr,
type, pkgRegistry, timestampField, pkg );
if (results != null) {
type.setTimestampExtractor(pkg.getFieldExtractor( type,
timestampField, results.getReturnType() ));
} else {
resultCollector.addBuilderResult(new
TypeDeclarationError(typeDescr,
- "Error
creating field accessors for timestamp field '" + timestamp +
+ "Error
creating field accessors for timestamp field '" + timestampField +
"' for type
'" + type.getTypeName() + "'"));
}
}
}
- private static void wireDurationAccessor(TypeDeclarationContext context,
BuildResultCollector resultCollector, Annotated annotated, TypeDeclaration
type, PackageRegistry pkgRegistry ) {
- Duration duration = annotated.getTypedAnnotation(Duration.class);
- if (duration != null) {
- BaseDescr typeDescr = annotated instanceof BaseDescr ? (
(BaseDescr) annotated ) : new BaseDescr();
- String durationField;
- try {
- durationField = duration.value();
- } catch (Exception e) {
- resultCollector.addBuilderResult(new
TypeDeclarationError(typeDescr, e.getMessage()));
- return;
- }
- type.setDurationAttribute(durationField);
+ private static void wireDurationAccessor(TypeDeclarationContext context,
BuildResultCollector resultCollector, BaseDescr typeDescr, TypeDeclaration
type, PackageRegistry pkgRegistry ) {
+ String durationField = type.getDurationAttribute();
+ if (durationField != null) {
InternalKnowledgePackage pkg = pkgRegistry.getPackage();
-
AnalysisResult results = getMvelAnalysisResult(context, typeDescr,
type, pkgRegistry, durationField, pkg );
if (results != null) {
type.setDurationExtractor(pkg.getFieldExtractor( type,
durationField, results.getReturnType() ));
diff --git
a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationFactory.java
b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationFactory.java
index 72564ce5159..50d722d2e0a 100644
---
a/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationFactory.java
+++
b/drools-compiler/src/main/java/org/drools/compiler/builder/impl/TypeDeclarationFactory.java
@@ -38,14 +38,13 @@ import org.drools.drl.ast.descr.EnumDeclarationDescr;
import org.drools.drl.ast.descr.TypeDeclarationDescr;
import org.drools.drl.ast.descr.TypeFieldDescr;
import org.kie.api.definition.type.FactField;
-import org.kie.api.definition.type.PropertyChangeSupport;
-import org.kie.api.definition.type.Role;
import org.kie.api.definition.type.TypeSafe;
import org.kie.internal.builder.conf.PropertySpecificOption;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static
org.drools.compiler.rule.builder.util.AnnotationFactory.getTypedAnnotation;
+import static
org.drools.compiler.rule.builder.util.AnnotationFactory.toAnnotated;
public class TypeDeclarationFactory {
private static final Logger LOG =
LoggerFactory.getLogger(TypeDeclarationFactory.class);
@@ -66,45 +65,28 @@ public class TypeDeclarationFactory {
type = new TypeDeclaration( typeDescr.getTypeName() );
type.setResource( typeDescr.getResource() );
- // if is not new, search the already existing declaration and
- // compare them o see if they are at least compatibles
- // check whether it is necessary to build the class or not
Class<?> existingClass =
TypeDeclarationUtils.getExistingDeclarationClass( typeDescr, pkgRegistry );
type.setTypeClass( existingClass );
type.setNovel( existingClass == null );
type.setNature( existingClass == null ?
TypeDeclaration.Nature.DEFINITION : TypeDeclaration.Nature.DECLARATION );
-
- // Pre-populate from Java class annotations so that
finalizeConfigurator()
- // (which runs before wireFieldAccessors) sees the correct role,
expiration,
- // reactivity, and dynamic settings. DRL annotations applied next
will override.
- if ( existingClass != null ) {
- TypeDeclaration.processTypeAnnotations( type,
- new Annotated.ClassAdapter( existingClass ),
- context.getBuilderConfiguration().getOption(
PropertySpecificOption.KEY ) );
- }
}
- processTypeAnnotations(typeDescr, type);
- return type;
- }
-
- private void processTypeAnnotations( AbstractClassTypeDeclarationDescr
typeDescr, TypeDeclaration type ) {
try {
- processAnnotations( typeDescr, type );
+ processAnnotations( typeDescr, type,
context.getBuilderConfiguration().getOption( PropertySpecificOption.KEY ) );
} catch (Exception e) {
results.addBuilderResult(new TypeDeclarationError(typeDescr,
e.getMessage() ) );
}
+ return type;
}
- // Processes annotations from the DRL descriptor, overriding values
pre-populated from
- // Java class annotations in processTypeDeclaration(). Runs before
finalizeConfigurator(),
- // which needs @Role and @PropertyChangeSupport already set.
- public static void processAnnotations( AbstractClassTypeDeclarationDescr
typeDescr, TypeDeclaration type ) {
- Role role = getTypedAnnotation(typeDescr, Role.class);
- if (role != null) {
- type.setRole(role.value());
+ public static void processAnnotations( AbstractClassTypeDeclarationDescr
typeDescr, TypeDeclaration type, PropertySpecificOption propertySpecificOption
) {
+ Annotated annotated = toAnnotated(typeDescr);
+ if (type.getTypeClass() != null) {
+ annotated = Annotated.withFallback(annotated, new
Annotated.ClassAdapter(type.getTypeClass()));
}
+ TypeDeclaration.processTypeAnnotations( type, annotated,
propertySpecificOption );
+ // @TypeSafe is read from DRL only, not from the Java class (see
AlignAnnotationTest)
TypeSafe typeSafe = getTypedAnnotation(typeDescr, TypeSafe.class);
if (typeSafe != null) {
type.setTypesafe(typeSafe.value());
@@ -115,10 +97,6 @@ public class TypeDeclarationFactory {
} else if (typeDescr instanceof TypeDeclarationDescr &&
((TypeDeclarationDescr)typeDescr).isTrait()) {
type.setKind(TypeDeclaration.Kind.TRAIT);
}
-
- if (typeDescr.hasAnnotation(PropertyChangeSupport.class)) {
- type.setDynamic(true);
- }
}
protected void checkRedeclaration( AbstractClassTypeDeclarationDescr
typeDescr, TypeDeclaration type, PackageRegistry pkgRegistry ) {
@@ -253,8 +231,9 @@ public class TypeDeclarationFactory {
}
}
- //different duration -> Incompatible
- if (!nullSafeEqualityComparison(oldDeclaration.getDurationAttribute(),
newDeclaration.getDurationAttribute())) {
+ //different duration -> Incompatible (a redeclaration may add a
duration, but not change or remove it)
+ if (oldDeclaration.getDurationAttribute() != null
+ &&
!nullSafeEqualityComparison(oldDeclaration.getDurationAttribute(),
newDeclaration.getDurationAttribute())) {
throw new IncompatibleClassChangeError("Type Declaration " +
newDeclaration.getTypeName() + " has a different"
+ " duration: " +
newDeclaration.getDurationAttribute()
+ " != " +
oldDeclaration.getDurationAttribute());
diff --git
a/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/internal/ImpactModelBuilderImpl.java
b/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/internal/ImpactModelBuilderImpl.java
index ba5c8377876..5668e627538 100644
---
a/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/internal/ImpactModelBuilderImpl.java
+++
b/drools-impact-analysis/drools-impact-analysis-parser/src/main/java/org/drools/impact/analysis/parser/internal/ImpactModelBuilderImpl.java
@@ -28,6 +28,7 @@ import
org.drools.compiler.builder.impl.TypeDeclarationFactory;
import org.drools.compiler.builder.impl.processors.AnnotationNormalizer;
import
org.drools.compiler.builder.impl.processors.OtherDeclarationCompilationPhase;
import org.drools.compiler.compiler.PackageRegistry;
+import org.drools.compiler.compiler.TypeDeclarationError;
import org.drools.compiler.lang.descr.CompositePackageDescr;
import org.drools.base.definitions.InternalKnowledgePackage;
import org.drools.base.rule.TypeDeclaration;
@@ -45,6 +46,7 @@ import org.drools.util.StringUtils;
import org.kie.api.builder.ReleaseId;
import org.kie.api.io.Resource;
import org.kie.internal.builder.conf.LanguageLevelOption;
+import org.kie.internal.builder.conf.PropertySpecificOption;
import static java.util.Collections.emptyList;
import static
org.drools.compiler.builder.impl.ClassDefinitionFactory.createClassDefinition;
@@ -197,16 +199,24 @@ public class ImpactModelBuilderImpl extends
KnowledgeBuilderImpl {
if (hasMvel()) {
type.setTypeClassDef( createClassDefinition( typeClass,
typeDescr.getResource() ) );
}
- TypeDeclarationFactory.processAnnotations(typeDescr, type);
+ processAnnotations(typeDescr, type);
getOrCreatePackageRegistry(new
PackageDescr(typePkg)).getPackage().addTypeDeclaration(type );
} catch (ClassNotFoundException e) {
TypeDeclaration type = new TypeDeclaration(
typeDescr.getTypeName() );
type.setResource( typeDescr.getResource() );
- TypeDeclarationFactory.processAnnotations(typeDescr, type);
+ processAnnotations(typeDescr, type);
pkg.addTypeDeclaration( type );
}
}
+ private void processAnnotations(AbstractClassTypeDeclarationDescr
typeDescr, TypeDeclaration type) {
+ try {
+ TypeDeclarationFactory.processAnnotations(typeDescr, type,
getBuilderConfiguration().getOption(PropertySpecificOption.KEY));
+ } catch (Exception e) {
+ addBuilderResult(new TypeDeclarationError(typeDescr,
e.getMessage()));
+ }
+ }
+
protected void buildRules(Collection<CompositePackageDescr> packages) {
if (hasErrors()) { // if Error while generating pojo do not try
compile rule as they very likely depends hence fail too.
return;
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/DeclaredTypeCompilationPhase.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/DeclaredTypeCompilationPhase.java
index e72d2405b3a..0b3bfaecbfb 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/DeclaredTypeCompilationPhase.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/DeclaredTypeCompilationPhase.java
@@ -33,6 +33,7 @@ import
org.drools.model.codegen.execmodel.CanonicalModelBuildContext;
import org.drools.model.codegen.execmodel.PackageModelManager;
import org.drools.model.codegen.execmodel.generator.declaredtype.POJOGenerator;
import org.kie.internal.builder.KnowledgeBuilderResult;
+import org.kie.internal.builder.conf.PropertySpecificOption;
import static java.util.Arrays.asList;
@@ -59,7 +60,7 @@ public class DeclaredTypeCompilationPhase implements
CompilationPhase {
@Override
public void process() {
List<CompilationPhase> phases = asList(
- iteratingPhase((reg, acc) -> new
DeclaredTypeRegistrationPhase(reg, acc, pkgRegistryManager)),
+ iteratingPhase((reg, acc) -> new
DeclaredTypeRegistrationPhase(reg, acc, pkgRegistryManager,
buildConfiguration.getOption(PropertySpecificOption.KEY))),
iteratingPhase((reg, acc) ->
new POJOGenerator(reg.getPackage(), acc,
packageModelManager.getPackageModel(acc, reg, reg.getPackage().getName()),
packages, pkgRegistryManager)),
new GeneratedPojoCompilationPhase(
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/DeclaredTypeRegistrationPhase.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/DeclaredTypeRegistrationPhase.java
index cd37a419e75..94789eaa9a4 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/DeclaredTypeRegistrationPhase.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/execmodel/processors/DeclaredTypeRegistrationPhase.java
@@ -23,6 +23,7 @@ import
org.drools.compiler.builder.impl.TypeDeclarationFactory;
import
org.drools.compiler.builder.impl.processors.AbstractPackageCompilationPhase;
import org.drools.compiler.builder.impl.processors.AnnotationNormalizer;
import org.drools.compiler.compiler.PackageRegistry;
+import org.drools.compiler.compiler.TypeDeclarationError;
import org.drools.base.definitions.InternalKnowledgePackage;
import org.drools.base.rule.TypeDeclaration;
import org.drools.drl.ast.descr.AbstractClassTypeDeclarationDescr;
@@ -32,6 +33,7 @@ import org.drools.drl.ast.descr.PackageDescr;
import org.drools.drl.ast.descr.TypeDeclarationDescr;
import org.drools.model.codegen.execmodel.errors.UnsupportedFeatureError;
import org.drools.util.TypeResolver;
+import org.kie.internal.builder.conf.PropertySpecificOption;
import static
org.drools.compiler.builder.impl.ClassDefinitionFactory.createClassDefinition;
import static org.drools.base.util.Drools.hasMvel;
@@ -39,10 +41,12 @@ import static org.drools.base.util.Drools.hasMvel;
public class DeclaredTypeRegistrationPhase extends
AbstractPackageCompilationPhase {
private final PackageRegistryManager pkgRegistryManager;
+ private final PropertySpecificOption propertySpecificOption;
- public DeclaredTypeRegistrationPhase(PackageRegistry pkgRegistry,
PackageDescr packageDescr, PackageRegistryManager pkgRegistryManager) {
+ public DeclaredTypeRegistrationPhase(PackageRegistry pkgRegistry,
PackageDescr packageDescr, PackageRegistryManager pkgRegistryManager,
PropertySpecificOption propertySpecificOption) {
super(pkgRegistry, packageDescr);
this.pkgRegistryManager = pkgRegistryManager;
+ this.propertySpecificOption = propertySpecificOption;
}
@Override
@@ -68,7 +72,7 @@ public class DeclaredTypeRegistrationPhase extends
AbstractPackageCompilationPha
if (hasMvel()) {
type.setTypeClassDef( createClassDefinition( typeClass,
typeDescr.getResource() ) );
}
- TypeDeclarationFactory.processAnnotations(typeDescr, type);
+ processAnnotations(typeDescr, type);
if (!type.isTypesafe()) {
results.addBuilderResult(new
UnsupportedFeatureError("@typesafe(false) is not supported in executable model
: " + type));
}
@@ -77,11 +81,19 @@ public class DeclaredTypeRegistrationPhase extends
AbstractPackageCompilationPha
} catch (ClassNotFoundException e) {
TypeDeclaration type = new TypeDeclaration(
typeDescr.getTypeName() );
type.setResource( typeDescr.getResource() );
- TypeDeclarationFactory.processAnnotations(typeDescr, type);
+ processAnnotations(typeDescr, type);
pkg.addTypeDeclaration( type );
}
}
+ private void processAnnotations(AbstractClassTypeDeclarationDescr
typeDescr, TypeDeclaration type) {
+ try {
+ TypeDeclarationFactory.processAnnotations(typeDescr, type,
propertySpecificOption);
+ } catch (Exception e) {
+ results.addBuilderResult(new TypeDeclarationError(typeDescr,
e.getMessage()));
+ }
+ }
+
protected void normalizeAnnotations(AnnotatedBaseDescr
annotationsContainer, TypeResolver typeResolver, boolean isStrict) {
AnnotationNormalizer annotationNormalizer =
AnnotationNormalizer.of(
diff --git
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/tool/ExplicitCanonicalModelCompiler.java
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/tool/ExplicitCanonicalModelCompiler.java
index 6fdbc70abf0..62f06961349 100644
---
a/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/tool/ExplicitCanonicalModelCompiler.java
+++
b/drools-model/drools-model-codegen/src/main/java/org/drools/model/codegen/tool/ExplicitCanonicalModelCompiler.java
@@ -55,6 +55,7 @@ import
org.drools.model.codegen.execmodel.processors.GeneratedPojoCompilationPha
import org.drools.model.codegen.execmodel.processors.ModelGeneratorPhase;
import org.drools.model.codegen.execmodel.processors.PojoStoragePhase;
import org.drools.model.codegen.execmodel.processors.SourceCodeGenerationPhase;
+import org.kie.internal.builder.conf.PropertySpecificOption;
import org.kie.util.maven.support.ReleaseIdImpl;
/**
@@ -129,7 +130,7 @@ public class ExplicitCanonicalModelCompiler<T extends
PackageSources> {
public void process() {
List<CompilationPhase> phases = new ArrayList<>();
- phases.add(iteratingPhase((reg, acc) -> new
DeclaredTypeRegistrationPhase(reg, acc, pkgRegistryManager)));
+ phases.add(iteratingPhase((reg, acc) -> new
DeclaredTypeRegistrationPhase(reg, acc, pkgRegistryManager,
configuration.getOption(PropertySpecificOption.KEY))));
phases.add(iteratingPhase((reg, acc) ->
new POJOGenerator(reg.getPackage(), acc,
packageModelManager.getPackageModel(acc, reg, reg.getPackage().getName()),
packages, pkgRegistryManager)));
phases.add(new GeneratedPojoCompilationPhase(
diff --git
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/DeclaredTypesTest.java
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/DeclaredTypesTest.java
index a599fad156b..a0d4ae3a559 100644
---
a/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/DeclaredTypesTest.java
+++
b/drools-model/drools-model-codegen/src/test/java/org/drools/model/codegen/execmodel/DeclaredTypesTest.java
@@ -912,4 +912,21 @@ public class DeclaredTypesTest extends BaseModelTest {
.containsExactlyInAnyOrder("Unknown annotation property yyy",
"Unknown annotation property zzz");
}
+
+ @ParameterizedTest
+ @MethodSource("parameters")
+ void testInvalidAnnotationValueReportsBuildError(RUN_TYPE runType) {
+ String str = "package org.example.invalid; \n" +
+ "declare Foo\n" +
+ " @role( event )\n" +
+ " @expires( abc )\n" +
+ " name : String\n" +
+ "end";
+
+ Results results = createKieBuilder(runType, str).getResults();
+
+ assertThat(results.getMessages(Message.Level.ERROR))
+ .extracting(Message::getText)
+ .anyMatch(text -> text.contains("Error parsing time string: [
abc ]"));
+ }
}
\ No newline at end of file
diff --git
a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/util/TypeDeclarationUtil.java
b/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/util/TypeDeclarationUtil.java
index be2c5611d87..a298feeca50 100644
---
a/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/util/TypeDeclarationUtil.java
+++
b/drools-model/drools-model-compiler/src/main/java/org/drools/modelcompiler/util/TypeDeclarationUtil.java
@@ -39,11 +39,9 @@ import
org.drools.modelcompiler.constraints.LambdaFieldReader;
import org.drools.modelcompiler.constraints.LambdaReadAccessor;
import org.drools.util.ClassUtils;
import org.drools.util.TypeResolver;
-import org.kie.api.definition.type.Duration;
import org.kie.api.definition.type.Expires;
import org.kie.api.definition.type.Position;
import org.kie.api.definition.type.Role;
-import org.kie.api.definition.type.Timestamp;
import org.kie.internal.builder.conf.PropertySpecificOption;
import static
org.drools.base.rule.TypeDeclaration.createTypeDeclarationForBean;
@@ -63,7 +61,7 @@ public class TypeDeclarationUtil {
new AccessibleClassDefinition( typeClass, typeResolver ) :
new DynamicClassDefinition( typeClass ) );
- wireClassAnnotations( typeClass, typeDeclaration );
+ wireTimeAccessors( typeDeclaration );
wireMetaTypeAnnotations( metaType, typeDeclaration );
wireFields(typeClass, typeDeclaration);
@@ -157,15 +155,13 @@ public class TypeDeclarationUtil {
}
}
- private static void wireClassAnnotations( Class<?> typeClass,
TypeDeclaration typeDeclaration ) {
- Duration duration = typeClass.getAnnotation( Duration.class );
- if (duration != null) {
- wireDurationAccessor( duration.value(), typeDeclaration );
+ // the attribute names were already set from the class annotations by
createTypeDeclarationForBean()
+ private static void wireTimeAccessors( TypeDeclaration typeDeclaration ) {
+ if (typeDeclaration.getDurationAttribute() != null) {
+ wireDurationAccessor( typeDeclaration.getDurationAttribute(),
typeDeclaration );
}
-
- Timestamp timestamp = typeClass.getAnnotation( Timestamp.class );
- if (timestamp != null) {
- wireTimestampAccessor( timestamp.value(), typeDeclaration );
+ if (typeDeclaration.getTimestampAttribute() != null) {
+ wireTimestampAccessor( typeDeclaration.getTimestampAttribute(),
typeDeclaration );
}
}
@@ -179,16 +175,7 @@ public class TypeDeclarationUtil {
public static TypeDeclaration createTypeDeclaration(Class<?> cls,
PropertySpecificOption propertySpecificOption) {
TypeDeclaration typeDeclaration = createTypeDeclarationForBean( cls,
propertySpecificOption );
-
- Duration duration = cls.getAnnotation( Duration.class );
- if (duration != null) {
- wireDurationAccessor( duration.value(), typeDeclaration );
- }
- Timestamp timestamp = cls.getAnnotation( Timestamp.class );
- if (timestamp != null) {
- wireTimestampAccessor( timestamp.value(), typeDeclaration );
- }
-
+ wireTimeAccessors( typeDeclaration );
return typeDeclaration;
}
diff --git
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/compiler/TypeDeclarationTest.java
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/compiler/TypeDeclarationTest.java
index 9a4f1ca37a9..1dc9bd547ed 100644
---
a/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/compiler/TypeDeclarationTest.java
+++
b/drools-test-coverage/test-compiler-integration/src/test/java/org/drools/mvel/compiler/compiler/TypeDeclarationTest.java
@@ -40,6 +40,7 @@ import org.drools.testcoverage.common.util.KieBaseUtil;
import org.drools.testcoverage.common.util.KieUtil;
import org.drools.testcoverage.common.util.TestConstants;
import org.drools.testcoverage.common.util.TestParametersUtil2;
+import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.MethodSource;
import org.kie.api.KieBase;
@@ -149,6 +150,96 @@ public class TypeDeclarationTest {
}
+ private static final String EVENT_WITH_DURATION =
+ "package org.kie \n" +
+ "declare org.kie.EventA \n" +
+ " @role (event) \n" +
+ " @duration (duration) \n" +
+ " name : String \n" +
+ " duration : Long \n" +
+ " duration2 : Long \n" +
+ "end \n";
+
+ @Test
+ public void testDurationRedeclarationWithSameDuration() {
+ KnowledgeBuilder kbuilder = buildTwice(EVENT_WITH_DURATION,
EVENT_WITH_DURATION);
+
+
assertThat(kbuilder.hasErrors()).as(kbuilder.getErrors().toString()).isFalse();
+ TypeDeclaration typeDeclaration =
((KnowledgePackageImpl)kbuilder.getKnowledgePackages().iterator().next()).getTypeDeclaration("EventA");
+
assertThat(typeDeclaration.getDurationAttribute()).isEqualTo("duration");
+ }
+
+ @Test
+ public void testDurationRedeclarationWithoutDurationKeepsIt() {
+ String str2 = EVENT_WITH_DURATION.replace(" @duration (duration)
\n", "");
+
+ KnowledgeBuilder kbuilder = buildTwice(EVENT_WITH_DURATION, str2);
+
+
assertThat(kbuilder.hasErrors()).as(kbuilder.getErrors().toString()).isFalse();
+ TypeDeclaration typeDeclaration =
((KnowledgePackageImpl)kbuilder.getKnowledgePackages().iterator().next()).getTypeDeclaration("EventA");
+
assertThat(typeDeclaration.getDurationAttribute()).isEqualTo("duration");
+ }
+
+ @Test
+ public void testDurationRedeclarationWithDifferentDuration() {
+ String str2 = EVENT_WITH_DURATION.replace("@duration (duration)",
"@duration (duration2)");
+
+ KnowledgeBuilder kbuilder = buildTwice(EVENT_WITH_DURATION, str2);
+
+ assertThat(kbuilder.getErrors().toString()).contains("has a different
duration: duration2 != duration");
+ }
+
+ private static final String FACT_FOO =
+ "package org.kie \n" +
+ "declare org.kie.Foo \n" +
+ " name : String \n" +
+ "end \n";
+
+ private static String redeclareFoo(String annotations) {
+ return "package org.kie \n" +
+ "declare org.kie.Foo \n" +
+ " " + annotations + " \n" +
+ "end \n";
+ }
+
+ private static TypeDeclaration getFooAfterRedeclaration(String drl1,
String drl2) {
+ KnowledgeBuilder kbuilder = buildTwice(drl1, drl2);
+
assertThat(kbuilder.hasErrors()).as(kbuilder.getErrors().toString()).isFalse();
+ return
((KnowledgePackageImpl)kbuilder.getKnowledgePackages().iterator().next()).getTypeDeclaration("Foo");
+ }
+
+ @Test
+ public void testRedeclarationWithClassReactive() {
+ TypeDeclaration typeDeclaration = getFooAfterRedeclaration(FACT_FOO,
redeclareFoo("@classReactive"));
+ assertThat(typeDeclaration.isPropertyReactive()).isFalse();
+ }
+
+ @Test
+ public void testRedeclarationWithPropertyChangeSupport() {
+ TypeDeclaration typeDeclaration = getFooAfterRedeclaration(FACT_FOO,
redeclareFoo("@propertyChangeSupport"));
+ assertThat(typeDeclaration.isDynamic()).isTrue();
+ }
+
+ @Test
+ public void testRedeclarationWithRoleFact() {
+ String eventFoo = FACT_FOO.replace("declare org.kie.Foo \n", "declare
org.kie.Foo \n @role (event) \n");
+ TypeDeclaration typeDeclaration = getFooAfterRedeclaration(eventFoo,
redeclareFoo("@role(fact)"));
+ assertThat(typeDeclaration.getRole()).isEqualTo(Role.Type.FACT);
+ }
+
+ @Test
+ public void testRedeclarationWithExpiresWithoutRole() {
+ TypeDeclaration typeDeclaration = getFooAfterRedeclaration(FACT_FOO,
redeclareFoo("@expires(10s)"));
+ assertThat(typeDeclaration.getExpirationOffset()).isEqualTo(10_000L);
+ }
+
+ private static KnowledgeBuilder buildTwice(String drl1, String drl2) {
+ KnowledgeBuilder kbuilder =
KnowledgeBuilderFactory.newKnowledgeBuilder();
+ kbuilder.add( ResourceFactory.newByteArrayResource( drl1.getBytes() ),
ResourceType.DRL );
+ kbuilder.add( ResourceFactory.newByteArrayResource( drl2.getBytes() ),
ResourceType.DRL );
+ return kbuilder;
+ }
+
@ParameterizedTest(name = "KieBase type={0}")
@MethodSource("parameters")
public void testNoAnnotationUpdateIfError(){
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]