package example;

import static org.assertj.core.api.Assertions.assertThat;

import java.net.URI;

import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.test.context.junit.jupiter.SpringJUnitConfig;

@SpringJUnitConfig
class URITests {

    private static final String URL = "http://username:p%40ssword@localhost/test";
    private static final String USER_INFO = "username:p@ssword";

    @Value(URL)
    private URI uri;

    @Test
    void testConversionService() {
        assertUserInfo(DefaultConversionService.getSharedInstance().convert(URL, URI.class));
    }

    @Test
    void testURI() throws Exception {
        assertUserInfo(new URI(URL));
    }

    @Test
    void testBind() {
        assertUserInfo(this.uri);
    }

    private void assertUserInfo(URI uri) {
        assertThat(uri.getUserInfo()).isEqualTo(USER_INFO);
    }
}

Two tests pass but one test failed with:

org.opentest4j.AssertionFailedError: 
expected: "username:p@ssword"
 but was: "username:p%40ssword"
    at example.URITests.assertUserInfo(URITests.java:37)
    at example.URITests.testBind(URITests.java:33)
    at java.base/java.lang.reflect.Method.invoke(Method.java:580)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)
    at java.base/java.util.ArrayList.forEach(ArrayList.java:1596)

plugins {
    id 'java'
    id 'org.springframework.boot' version '3.5.4'
    id 'io.spring.dependency-management' version 'latest.release'
}

group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '21'

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
}

tasks.named('test') {
    useJUnitPlatform()
}

Comment From: quaff

I think it's a bug of URIEditor.

Comment From: sbrannen

The behavior you've encountered results from the fact that the default registered URIEditor is configured with encoding enabled.

If you add the following to your test class, all 3 tests will pass.

@Configuration
static class Config {

    @Bean
    static BeanFactoryPostProcessor customUriEditorRegistrar() {
        return beanFactory -> beanFactory.addPropertyEditorRegistrar(
                registry -> registry.registerCustomEditor(URI.class, new URIEditor(false)));
    }
}

Comment From: quaff

The behavior you've encountered results from the fact that the default registered URIEditor is configured with encoding enabled.

Yes, I confirmed it before reporting this issue. I think it's a bug: currently there is no way to support @ in password with unencoded path.

Comment From: sbrannen

Related Issues and Commits

  • Commit 2fde8ef4d9deb333f22cb10005e7187d1a0b0888
  • Commit 7ec9f1506a3d93a5dacc66c00aec5ca6943a5ae7
  • 10673

  • 11743

  • 21123

  • 34262

Comment From: sbrannen

Please note that this is effectively a:

  • Duplicate of #34262