Skip to content

Unable to register MBean - Invalid character `:' in value #3051

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Stiuil06 opened this issue Sep 4, 2019 · 18 comments
Closed

Unable to register MBean - Invalid character `:' in value #3051

Stiuil06 opened this issue Sep 4, 2019 · 18 comments
Labels
status: declined There won't be a fix for some reason

Comments

@Stiuil06
Copy link

Stiuil06 commented Sep 4, 2019

Hi all.
I have similar(I think) issues to spring-cloud-stream/#1497 when I try run application to listening mqtt broker.
Im trying to run this code:
https://docs.spring.io/spring-integration/docs/5.2.0.BUILD-SNAPSHOT/reference/html/mqtt.html#configuring-with-the-java-dsl
Configuring with the Java DSL

for Configuring with Java Configuration everything works.

My stacktrace

org.springframework.jmx.export.UnableToRegisterMBeanException: Unable to register MBean [mqttInbound.mqtt:inbound-channel-adapter#0] with key 'mqttInbound.mqtt:inbound-channel-adapter#0'; nested exception is javax.management.MalformedObjectNameException: Invalid character `:' in value
	at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:625) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.lambda$registerBeans$2(MBeanExporter.java:551) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at java.base/java.util.HashMap.forEach(HashMap.java:1333) ~[na:na]
	at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:551) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:434) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:862) ~[spring-beans-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:877) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:743) ~[spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:390) ~[spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:312) ~[spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1214) ~[spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1203) ~[spring-boot-2.1.7.RELEASE.jar:2.1.7.RELEASE]
	at com.firstnamelastname.grl.MiddlewareApplication.main(MiddlewareApplication.java:10) ~[classes/:na]
Caused by: javax.management.MalformedObjectNameException: Invalid character `:' in value
	at java.management/javax.management.ObjectName.parseValue(ObjectName.java:978) ~[na:na]
	at java.management/javax.management.ObjectName.checkValue(ObjectName.java:1010) ~[na:na]
	at java.management/javax.management.ObjectName.construct(ObjectName.java:729) ~[na:na]
	at java.management/javax.management.ObjectName.<init>(ObjectName.java:1450) ~[na:na]
	at java.management/javax.management.ObjectName.getInstance(ObjectName.java:1356) ~[na:na]
	at org.springframework.jmx.support.ObjectNameManager.getInstance(ObjectNameManager.java:99) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.jmx.export.naming.MetadataNamingStrategy.getObjectName(MetadataNamingStrategy.java:135) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.boot.autoconfigure.jmx.ParentAwareNamingStrategy.getObjectName(ParentAwareNamingStrategy.java:59) ~[spring-boot-autoconfigure-2.1.7.RELEASE.jar:2.1.7.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.getObjectName(MBeanExporter.java:755) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:654) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:615) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	... 13 common frames omitted

My code

public class MeasurementListener {

    @Bean
    public IntegrationFlow mqttInbound() {
        return IntegrationFlows.from(
                new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883", "/measurement/+/+"))
                .handle(m -> System.out.println(m.getPayload()))
                .get();
    }

}

My main pom

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.firstnamelastname</groupId>
    <artifactId>grl</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>green-real-time</name>
    <description>Green Real Time</description>

    <packaging>pom</packaging>
    <modules>
        <module>grl-core</module>
        <module>grl-firmware-simulator</module>
        <module>grl-middleware</module>
    </modules>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.1.7.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>12</java.version>
        <maven.compiler.source>${java.version}</maven.compiler.source>
        <maven.compiler.target>${java.version}</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-release-plugin</artifactId>
                <configuration>
                    <goals>install</goals>
                    <autoVersionSubmodules>true</autoVersionSubmodules>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

pom for this module

<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <parent>
        <groupId>com.firstnamelastname</groupId>
        <artifactId>grl</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>

    <artifactId>grl-middleware</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>green-real-time-middleware</name>
    <description>Green Real Time - Middleware</description>

    <properties>
        <spring-boot.repackage.skip>true</spring-boot.repackage.skip>
    </properties>

    <dependencies>
        <dependency>
            <groupId>com.firstnamelastname</groupId>
            <artifactId>grl-core</artifactId>
            <version>0.0.1-SNAPSHOT</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-cassandra-reactive</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-mqtt</artifactId>
            <version>5.1.7.RELEASE</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>
@artembilan
Copy link
Member

The IntegrationMBeanExporter has this logic:

/*
	 * https://www.oracle.com/technetwork/java/javase/tech/best-practices-jsp-136021.html
	 *
	 * The set of characters in a value is also limited. If special characters may
	 * occur, it is recommended that the value be quoted, using ObjectName.quote. If
	 * the value for a given key is sometimes quoted, then it should always be quoted.
	 * By default, if a value is a string (rather than a number, say), then it should
	 * be quoted unless you are sure that it will never contain special characters.
	 */
	private String quoteIfNecessary(String name) {
		return SourceVersion.isName(name) ? name : ObjectName.quote(name);
	}

Looks like something similar must happen in Spring Boot or Spring Framework.
According provided stack trace, there is no Spring Integration involved:

	at java.management/javax.management.ObjectName.getInstance(ObjectName.java:1356) ~[na:na]
	at org.springframework.jmx.support.ObjectNameManager.getInstance(ObjectNameManager.java:99) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.jmx.export.naming.MetadataNamingStrategy.getObjectName(MetadataNamingStrategy.java:135) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.boot.autoconfigure.jmx.ParentAwareNamingStrategy.getObjectName(ParentAwareNamingStrategy.java:59) ~[spring-boot-autoconfigure-2.1.7.RELEASE.jar:2.1.7.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.getObjectName(MBeanExporter.java:755) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:654) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]
	at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:615) ~[spring-context-5.1.9.RELEASE.jar:5.1.9.RELEASE]

Although, you can add an explicit bean name for that MQTT endpoint to workaround this problem:

IntegrationFlows.from(
                new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883", "/measurement/+/+"), e -> e.id("myMqttEndpoint"))

@artembilan artembilan added the status: waiting-for-reporter Needs a feedback from the reporter label Sep 4, 2019
@Stiuil06
Copy link
Author

Stiuil06 commented Sep 4, 2019

Your workaround is enought for me. But I have problem with that:
image
image
And it doesn't compile...
I add casting (as told me IDE)
image
but now I have huge stacktrace in runtime (related to wrong casting)

MqttPahoMessageDrivenChannelAdapter not implement MessageSource.
It implement something like MessageProducerSupport

@artembilan
Copy link
Member

I mean the issue is there, but it is not a part of Spring Integration to fix.

@philwebb , any thoughts about quoting MBean names in Spring Boot?
Or let's push it down to Spring Framework then!

@artembilan
Copy link
Member

Oh! Sorry, @Stiuil06 . The MqttPahoMessageDrivenChannelAdapter is not a MessageSource. It has to be configured as a bean instead to get a proper bean name:

@Bean
public  MqttPahoMessageDrivenChannelAdapter myMqttEndpoint() {
    return  new MqttPahoMessageDrivenChannelAdapter("tcp://localhost:1883", "/measurement/+/+");
}
...
  @Bean
    public IntegrationFlow mqttInbound() {
        return IntegrationFlows.from(myMqttEndpoint())
...

@Stiuil06
Copy link
Author

Stiuil06 commented Sep 4, 2019

As I wrote in opening post in this case (Configuring with Java Configuration) it works, but not work for Configuring with the Java DSL. (I refer to that).

Now I notice, that im working on 5.1.7.RELEASE, and example from the above documentation is for 5.2.0.BUILD-SNAPSHOT. Maybe it will be work on this build.
How can I get this snapshot version? On mvnrepository the latest is 5.1.7.RELEASE.
(This is a training program so it is not important to use official releases)

@artembilan
Copy link
Member

On the other hand it is not clear how this Spring Integration component (marked with @IntegrationManagedResource) get processed by the regular org.springframework.jmx.export.MBeanExporter, since there is indeed appropriate auto-configuration:

	/**
	 * Spring Integration JMX configuration.
	 */
	@Configuration
	@ConditionalOnClass(EnableIntegrationMBeanExport.class)
	@ConditionalOnMissingBean(value = IntegrationMBeanExporter.class, search = SearchStrategy.CURRENT)
	@ConditionalOnBean(MBeanServer.class)
	@ConditionalOnProperty(prefix = "spring.jmx", name = "enabled", havingValue = "true", matchIfMissing = true)
	protected static class IntegrationJmxConfiguration implements EnvironmentAware, BeanFactoryAware {

and there is a MBeanExporterHelper bean anyway...

@Stiuil06 ,
one more time: your stack trace doesn't show any Spring Integration code. Only the problem that Spring Integration registers some bean which is not going to be properly exposed into JMX by that MBeanExporter in Spring Boot.
Therefore changing version for Spring Integration won't help you at all.

It looks like would be great if you can share a simple project with us to play with and reproduce.

Thanks for understanding.

@Stiuil06
Copy link
Author

Stiuil06 commented Sep 4, 2019

@artembilan I mean to change version of all spring components which I use. (boot etc.)

I create simple project with that issue.
https://github.com/Stiuil06/demo-mqtt-listener

Thanks for all your help and time.

@artembilan
Copy link
Member

OK. Another solution is for you like this:

<dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-jmx</artifactId>
</dependency>

So, all Spring Integration components are going to be registered in JMX by the Spring Integration mechanism.

Anyway I think we still have quoting problem in the regular Spring Boot/Spring Framework solution.

/CC @philwebb

@philwebb
Copy link
Member

philwebb commented Sep 4, 2019

Spring Boot is just delegating to MetadataNamingStrategy so I think it would be a Framework problem.

@artembilan
Copy link
Member

@Stiuil06 ,

would you mind sharing with us your final experience?
Plus, would you mind moving this issue into https://github.com/spring-projects/spring-framework/issues ?

It looks like we agreed with Spring Boot team that an issue has to be resolved on the core level if at all...

Thanks

@Stiuil06
Copy link
Author

Stiuil06 commented Sep 7, 2019

@artembilan
I just add

        <dependency>
            <groupId>org.springframework.integration</groupId>
            <artifactId>spring-integration-jmx</artifactId>
        </dependency>

as you advised, and it work for me.
I haven't explore subject more.

Sure, we should move issue to spring-framework.
Should I open a new issue there? Or maybe you have possibility to move it?

@artembilan
Copy link
Member

Great! Good to know that workaround has made it!

Well, looks like I don't have permissions to move issue over there.
Maybe @philwebb can do that for us, but I guess it is OK if you just open a new one over there with a link to this one.
Thanks

@Stiuil06
Copy link
Author

Stiuil06 commented Sep 8, 2019

@artembilan So I opened new issue there.
spring-projects/spring-framework#23608

@artembilan
Copy link
Member

Thanks, @Stiuil06 !

We will keep this issue opened until resolution on that SF one.
We may just remove the mention logic here in favor of a new one in SF.

@artembilan artembilan added status: waiting-for-triage The issue need to be evaluated and its future decided and removed status: waiting-for-reporter Needs a feedback from the reporter labels Sep 8, 2019
@dividebyzero
Copy link

google brought me here.. I think it is rather unfortunate that the quickstart given in documentation here:
https://docs.spring.io/spring-integration/reference/html/mqtt.html#configuring-with-the-java-dsl
leads to this error. adding
implementation 'org.springframework.integration:spring-integration-jmx'
to build.gradle fixes it as described, IMHO that should be mentioned in above documentation link.

@artembilan
Copy link
Member

@dividebyzero ,

I'm sorry to hear about your bad experience, but unfortunately that code snippet does nothing with JMX, so the problem you are facing is really out of that chapter scope.
What I'm afraid of even if we add some note into our JMX chapter, it is still not going to be opaque for end-users as you since you all just don't use that JMX module from Spring Integration. That's you who set spring.jmx.enabled=true on your Spring Boot application. Probably the best place is, of course, to mention naming quoting is still Spring Framework since everything in the end is based on it. See that linked issue for more info. Plus this: https://docs.spring.io/spring-framework/docs/current/reference/html/integration.html#jmx-naming

Of course, there is another workaround to provide a custom naming strategy instead of an out-of-the-box one in Spring Boot:

@Bean
@ConditionalOnMissingBean(value = ObjectNamingStrategy.class, search = SearchStrategy.CURRENT)
public ParentAwareNamingStrategy objectNamingStrategy() {

But this one not easier then just adding spring-integration-jmx dependency...

@StephanPraetsch
Copy link

As far as I can see this fix would solve my problem. Is that feasible? See also here for the reason.

@artembilan
Copy link
Member

The fix has landed in Spring Framework via: spring-projects/spring-framework#23608.

Nothing to do on Spring Integration side.

@artembilan artembilan closed this as not planned Won't fix, can't repro, duplicate, stale Nov 29, 2023
@artembilan artembilan added status: declined There won't be a fix for some reason and removed status: waiting-for-triage The issue need to be evaluated and its future decided labels Nov 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: declined There won't be a fix for some reason
Projects
None yet
Development

No branches or pull requests

5 participants