azure-sdk-for-java: [BUG] Hashmap to Map Cast Exception in TargetingFilter.java when using Application Configuration

Describe the bug When checking if a feature flag is enabled the exception java.lang.ClassCastException is thrown.

Exception or Stack Trace

Caused by: java.lang.ClassCastException: java.util.HashMap$Values cannot be cast to java.util.Map
	at com.azure.spring.cloud.feature.management.filters.TargetingFilter.evaluate(TargetingFilter.java:134) ~[spring-cloud-azure-feature-management-4.8.0.jar:4.8.0]
	at com.azure.spring.cloud.feature.management.FeatureManager.isFeatureOn(FeatureManager.java:114) ~[spring-cloud-azure-feature-management-4.8.0.jar:4.8.0]
	at com.azure.spring.cloud.feature.management.FeatureManager.lambda$checkFeature$2(FeatureManager.java:106) ~[spring-cloud-azure-feature-management-4.8.0.jar:4.8.0]
	at java.util.stream.MatchOps$1MatchSink.accept(MatchOps.java:90) ~[?:1.8.0_332]
	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) ~[?:1.8.0_332]
	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175) ~[?:1.8.0_332]
	at java.util.HashMap$ValueSpliterator.tryAdvance(HashMap.java:1673) ~[?:1.8.0_332]
	at java.util.stream.ReferencePipeline.forEachWithCancel(ReferencePipeline.java:126) ~[?:1.8.0_332]
	at java.util.stream.AbstractPipeline.copyIntoWithCancel(AbstractPipeline.java:499) ~[?:1.8.0_332]
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:486) ~[?:1.8.0_332]
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:472) ~[?:1.8.0_332]
	at java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:230) ~[?:1.8.0_332]
	at java.util.stream.MatchOps$MatchOp.evaluateSequential(MatchOps.java:196) ~[?:1.8.0_332]
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:1.8.0_332]
	at java.util.stream.ReferencePipeline.anyMatch(ReferencePipeline.java:516) ~[?:1.8.0_332]
	at com.azure.spring.cloud.feature.management.FeatureManager.checkFeature(FeatureManager.java:106) ~[spring-cloud-azure-feature-management-4.8.0.jar:4.8.0]
	at com.azure.spring.cloud.feature.management.FeatureManager.isEnabledAsync(FeatureManager.java:63) ~[spring-cloud-azure-feature-management-4.8.0.jar:4.8.0]
	at our java code

To Reproduce Setup an http request or a piece of code that attempts to check if a feature flag is enabled. Make sure the feature flag has a feature filter with the default percentage set to 0% and an allowed group that is set to 100%. Running this code will cause the cast exception to fire.

Code Snippet Here is my Java code that initiates the call to check if a flag is enabled: Boolean.TRUE.equals(featureManager.isEnabledAsync("someFeatureFlag").block())

This is the decompiled code that is throwing the exception from TargetingFilter.java:

Map<String, Map<String, Object>> exclusionMap = (Map<String, Map<String, Object>>) parameters
    .get(EXCLUSION);
Map<String, Object> exclusionAsLists = new HashMap<>();
if (exclusionMap != null) {
    exclusionAsLists.put(USERS, exclusionMap.getOrDefault(USERS, new HashMap<String, Object>()).values());
    exclusionAsLists.put(GROUPS, exclusionMap.getOrDefault(GROUPS, new HashMap<String, Object>()).values());
}

The error is specifically thrown on this line when the default branch is taken: exclusionAsLists.put(USERS, exclusionMap.getOrDefault(USERS, new HashMap<String, Object>()).values());

Expected behavior No cast exception is thrown, and that the feature flag check returns either a true or false.

Screenshots Here is the state of the debugger right before the exception is thrown: Screenshot 2023-07-11 at 10 32 55 AM

Setup (please complete the following information):

  • OS: MacOS 13.4.1 (22F82)
  • IDE: IntelliJ
  • Library/Libraries: spring-cloud-azure-feature-management-4.8.0.jar
  • Java version: 8
  • App Server/Environment: Tomcat
  • Frameworks: Spring Boot 2.7.12

If you suspect a dependency version mismatch (e.g. you see NoClassDefFoundError, NoSuchMethodError or similar), please check out Troubleshoot dependency version conflict article first. If it doesn’t provide solution for the problem, please provide:

  • verbose dependency tree (mvn dependency:tree -Dverbose)
  • exception message, full stack trace, and any available logs

Additional context I am using a remote configuration store. My local app is talking with a config store in the portal. It connects via a connection string.

Here are the related configured properties:

spring.cloud.azure.appconfiguration.enabled=true
spring.cloud.azure.appconfiguration.stores[0].feature-flags.enabled=true
spring.cloud.azure.appconfiguration.stores[0].connection-string=<Connection string redacted>
spring.cloud.azure.appconfiguration.stores[0].enabled=true
spring.cloud.azure.appconfiguration.stores[0].monitoring.enabled=true
spring.cloud.azure.appconfiguration.stores[0].monitoring.refresh-interval=30s
spring.cloud.azure.appconfiguration.stores[0].monitoring.triggers[0].key=sentinel
spring.cloud.azure.appconfiguration.stores[0].monitoring.feature-flag-refresh-interval=30s
spring.cloud.azure.appconfiguration.stores[0].feature-flags.selects[0].label-filter=,${spring.profiles.active}

The config store has one key/value called sentinel that allows for dynamic refresh and one feature flag with a feature filter. Here is a screenshot of the details. The value past Tenant: is a guid: Screenshot 2023-07-11 at 10 41 15 AM

Information Checklist Kindly make sure that you have added all the following information above and checkoff the required fields otherwise we will treat the issuer as an incomplete report

  • [-] Bug Description Added
  • [-] Repro Steps Added
  • [-] Setup information Added

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 28 (13 by maintainers)

Most upvoted comments

Reverting to 4.7.0 should fix this for now if you are running into this issue. PR is up for a fix for this https://github.com/Azure/azure-sdk-for-java/pull/35920.