OK, I decided that for the time being at least, I could provide defaults for
the problematic annotation methods. I still receive the
IllegalArgumentException I mentioned previously even though I made the
following change.
@ObjectClassDefinition(name = "BAM Query Metric Provider Configuration")
@interface QueryProviderConfig
{
String system();
String path();
int frequency() default 60;
Status status() default Status.Requested;
boolean postable() default false;
RuleType ruleType() default RuleType.Custom;
String ruleDef() default "";
ProviderType providerType();
String dataSource();
String queryFile();
String[] queryMods() default {};
String nameColumn() default "";
String valueColumn();
ValueColumnType valueColumnType() default ValueColumnType.INT;
}
There’s a bit of context that I left out last time though as I didn’t feel it
was important but perhaps it is. There another config type that contains a
subset of the above which is used to set values in a base class. To convert to
that type I use and anonymous interface as shown below.
@ObjectClassDefinition(name = "BAM Metric Provider Configuration")
public @interface MetricProviderConfig
{
String path() default "";
int frequency() default 60;
Status status() default Status.Requested;
boolean postable() default false;
RuleType ruleType() default RuleType.Custom;
String ruleDef() default "";
}
protected MetricProviderConfig toMPC(final QueryProviderConfig cfg)
throws Exception
{
return new MetricProviderConfig()
{
public Class<? extends Annotation> annotationType()
{
return MetricProviderConfig.class;
}
public String path()
{
return cfg.path();
}
public int frequency()
{
return cfg.frequency();
}
public Status status()
{
return cfg.status();
}
public boolean postable()
{
return cfg.postable();
}
public RuleType ruleType()
{
270: return cfg.ruleType(); // Exception thrown here
}
public String ruleDef()
{
return cfg.ruleDef();
}
};
}
The moderately interesting part of the traceback is as follows:
org.osgi.service.component.ComponentException:
java.lang.IllegalArgumentException: No enum constant
com.medline.bam.model.rule.IRule.RuleType.
at
org.apache.felix.scr.impl.inject.Annotations$Handler.invoke(Annotations.java:243)
at com.medline.bam.model.metric.provider.$Proxy28.ruleType(Unknown
Source)
at
com.medline.bam.model.metric.provider.QueryProvider$1.ruleType(QueryProvider.java:270)
at
com.medline.bam.model.metric.AbstractMetricProvider.update(AbstractMetricProvider.java:285)
at
com.medline.bam.model.metric.provider.AbstractQueryProvider.update(AbstractQueryProvider.java:241)
at
com.medline.bam.model.metric.provider.QueryProvider.activate(QueryProvider.java:288)
Here’s the activate method in QueryProvider. An instance of
MetricProviderConfig is passed into the object (not a component) that provides
most of the concrete implementation of the QueryProvider component. The config
is passed up to AbstractMetricProvider.update where cfg.ruleType() is invoked,
which causes the method in the anonymous interface to be invoked which causes
the exception.
@Activate
protected void activate(QueryProviderConfig cfg)
throws Exception
{
ISystem system = Utils.getSystem(systems, cfg.system());
if (system != null) {
setImpl(system, cfg);
288: getImpl().update(toMPC(cfg));
}
this.config = cfg;
}
The update method from AbstractMetricProvider:
protected void update(MetricProviderConfig cfg)
throws Exception
{
this.status = cfg.status();
this.postable = cfg.postable();
String[] ruleDef = (isBlank(cfg.ruleDef()) ? null :
cfg.ruleDef().split(","));
285: switch (cfg.ruleType())
{
Since cfg.ruleType() has a default, I would expect this to work but clearly
it’s not. It works fine as long as long as ruleType has an explicit value in
the .cfg file. The use of a default (in this context) seems to be the issue. Is
the use of the anonymous interface causing me problems perhaps? I wasn’t sure
how to make the conversion between types so I found that suggestion online.
I apologize for dumping all this out here but I’m kind of at a loss at this
point and I figured it was probably best to give as much context as might be
needed.
Regards,
Scott
From: Leschke, Scott [mailto:[email protected]]
Sent: Wednesday, September 07, 2016 10:31 AM
To: [email protected]
Subject: RE: configuration property types and enums
Thanks for the info. My experience / knowledge of annotation interfaces is
limited to say the least so that clears things up nicely. I’ll take a look at
the Felix extension per your recommendation. Thanks so much.
Scott
From: David Jencks [mailto:[email protected]]
Sent: Tuesday, September 06, 2016 6:37 PM
To: [email protected]<mailto:[email protected]>
Subject: Re: configuration property types and enums
OK, that’s pretty straightforward.
Annotations (@interface) can not return null values from their members. This is
a java language thing, not a DS thing. You need to assure either that your
configuration has an appropriate value or specify a default in the annotation.
You only get notified of the problem when you try to access the member.
Alternatively, you can use a felix extension allowing you to configure with an
interface, in which case null returns are allowed. You could define your
defaults directly in the @Component annotation property member. To do this
investigate the DSExt annotations in the org.apache.felix.scr.ext.anno bundle.
You’d use @DSExt.ConfigureWithInterfaces.
Hope this helps
david jencks
On Sep 6, 2016, at 2:08 PM, Leschke, Scott
<[email protected]<mailto:[email protected]>> wrote:
Yes, this is a DS component.
@Component(
configurationPid = "medline.bam.metric.provider.query",
configurationPolicy = ConfigurationPolicy.REQUIRE,
immediate = true
)
@Designate(ocd = QueryProviderConfig.class)
public class QueryProvider
Configuration Property Type: Name per
http://njbartlett.name/2015/08/17/osgir6-declarative-services.html
The CFP is the following:
@ObjectClassDefinition(name = "BAM Query Metric Provider Configuration")
@interface QueryProviderConfig
{
String system();
String path();
int frequency() default 60;
Status status() default Status.Requested;
boolean postable() default false;
RuleType ruleType();
String ruleDef() default "";
ProviderType providerType();
String dataSource();
String queryFile();
String[] queryMods() default {};
String nameColumn() default "";
String valueColumn();
ValueColumnType valueColumnType() default ValueColumnType.INT;
}
The exception occurs within the Activator when the method ruleType() of the CFP
is invoked.
I hesitate to post the code as it’s a bit more complicated but that’s the
upshot. My gut is telling me that since RuleType is an enum, it can’t be null,
although that make sense in this case. I can test it of course, by adding
“None” to the RuleType enum and setting the default to that but I’d prefer not
to unless that’s the expected approach.
From: David Jencks [mailto:[email protected]]
Sent: Tuesday, September 06, 2016 2:48 PM
To: [email protected]<mailto:[email protected]>
Subject: Re: configuration property types and enums
I have some guesses about what you might be talking about but it doesn’t all
make sense yet.This is a DS component, right? Could you be a lot more
specific, showing at least the activate method signature, whatever you mean by
configuration property type, the enum, and the stack trace? If you’ve used any
extra annotations on the component please show them too.
thanks
david jencks
On Sep 6, 2016, at 11:52 AM, Leschke, Scott
<[email protected]<mailto:[email protected]>> wrote:
I’m getting the following exception from an activate method.
org.osgi.service.component.ComponentException:
java.lang.IllegalArgumentException: No enum constant (Enumeration type name).
The activate method takes a Configuration Property Type that has a method that
returns a value of the type but does NOT have a default defined. The activate
method checks to see the method returns null. This is what I want but it seems
like it’s demanding that the Enum be non-null. Am I reading this correctly?
Must CFPs that return enums always return a valid value for the type?
Scott