Skip to content
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

Possibility to configure a custom WebJarAssetLocator [SPR-14092] #18664

Closed
spring-issuemaster opened this issue Mar 27, 2016 · 7 comments
Closed

Possibility to configure a custom WebJarAssetLocator [SPR-14092] #18664

spring-issuemaster opened this issue Mar 27, 2016 · 7 comments
Assignees
Milestone

Comments

@spring-issuemaster
Copy link
Collaborator

@spring-issuemaster spring-issuemaster commented Mar 27, 2016

Bartolom opened SPR-14092 and commented

The Spring Framework has a nice integration with. webjar-locator
https://github.com/webjars/webjars-locator
https://github.com/webjars/webjars-locator-core
#16928

Unfortunatly there is now way to configure the class org.webjars.WebJarAssetLocator. For instance I would like to provide my own configured instance or at least manipulate the Map behind org.webjars.WebJarAssetLocator.getFullPathIndex()

The instance used by Spring MVC is a private final field in WebJarsResourceResolver

private final WebJarAssetLocator webJarAssetLocator = new WebJarAssetLocator();

Replacing the WebJarsResourceResolver is also not easy as it is created with the new keyword in

There is a further related instantiation in

RootBeanDefinition webJarsResolverDef = new RootBeanDefinition(WebJarsResourceResolver.class);

It would be nice if I can provide the bean instance of WebJarAssetLocator by typical Spring dependency injection means, and Spring MVC will only create one if I don't suppy one.

Or if I can have at least access to the instance and can configure it further. WebMvcConfigurer would have beed the place where I expected it.

My usecase is that I'm using "Bower based WebJars" http://www.webjars.org/bower and they are generated automatically from Bower configuration files, which is great. But they are not as clean as we expect them to be in the Java-World.

I'm trying to find out if it is possbile to use Spring-Boot (with Gradle/Maven and without Bower) with WebJars to create Google/Vaadin Polymer Web Componenents.

So I have Web-Components-HTML-Import-Files in the webjars that reference other Web-Components-HTML-Import-Files in their HTML-source code, and they assume the typical Bower folder structure and use relative path and without version numbers.

I would be able to solve two of my issues when I would have access to the WebJarAssetLocator by some custom code of mine:

1.) Some of the webjars that I'm interested in, have ambigious resources.
/META-INF/resources/webjars/iron-ajax/1.2.0/iron-ajax.html
/META-INF/resources/webjars/iron-ajax/1.2.0/test/iron-ajax.html
(obviously I like to filter out the test-resources)

2.) Some of the generated resources have odd paths like:
/META-INF/resources/webjars/github-com-polymerlabs-promise-polyfill/1.0.0/promise-polyfill.html
where I would love to clean up the 'github-com-polymerlabs-'


Affects: 4.2.4

Referenced from: commits 9778408

@spring-issuemaster
Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 29, 2016

Stéphane Nicoll commented

Possible impact on Spring Boot.

@spring-issuemaster
Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 29, 2016

Bartolom commented

In my case I have a Spring Boot application, but I found the WebJar-Locator related source code in the main Spring Framework, so I filed the issue here.

If this could be solved in Spring Boot I'm happy with this as well.

@spring-issuemaster
Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 29, 2016

Stéphane Nicoll commented

Bartolom that was a remark for Brian. Since we support that feature, if we do some changes here it may have an impact on Spring Boot as well.

@spring-issuemaster
Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 30, 2016

Brian Clozel commented

We could address this by adding a new constructor to the WebJarsResourceResolver class so you can do the following.

With JavaConfig, registering manually a PathResourceResolver disables auto-registration and you get full control over the resource chain:

@Configuration
@EnableWebMvc
public class WebConfig extends WebMvcConfigurerAdapter {

    @Bean   
    public void WebJarAssetLocator webJarAssetLocator() {
        // ...
        return webJarAssetLocator;
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        WebJarAssetLocator webJarAssetLocator = webJarAssetLocator();
        WebJarsResourceResolver webjarsResourceResolver = new WebJarsResourceResolver(webJarAssetLocator);

        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public-resources/")
                .resourceChain(true)
                    .addResolver(webjarsResourceResolver)
                    .addResolver(new PathResourceResolver());
    }

}

With XML config, using the auto-registration="false" flag disables auto-registration and you get full control over the resource chain:

<mvc:resources mapping="/resources/**" location="/public-resources/">
    <mvc:resource-chain resource-cache="false" auto-registration="false">
        <mvc:resolvers>
            <ref bean="webjarsResourceResolver"/>
            <bean class="org.springframework.web.servlet.resource.PathResourceResolver"/>
        </mvc:resolvers>
    </mvc:resource-chain>
</mvc:resources>

<bean id="webjarsResourceResolver" class="org.springframework.web.servlet.resource.WebJarsResourceResolver">
    <constructor-arg value="webJarAssetLocator"/>
</bean>

What do you think?

@spring-issuemaster
Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 30, 2016

Bartolom commented

having the additional constructor WebJarsResourceResolver would be a possible solution.

But maybe as a general comment regarding the

disables auto-registration and you get full control over the resource chain

I'm always hesitant to do this. It seems that with each Spring MVC and Spring Boot release some well thought out features are added to the resource chain (e.g. browser caching). When another developer upgrades the Gradle/Maven dependency he/she might be wondering why the new feature are not popping up?
So one need to check what Spring Boot might have added lately and the essentially copy and paste it, to change the one line that one needs for customization.

Therefore I always like when there is a method in WebMvcConfigurerAdapter which I can override without messing with the other automatic configured stuff.

Maybe something like:

@Configuration
public class MyWebConfigurer extends WebMvcConfigurerAdapter

  // ...
  
  @Bean
  public WebJarAssetLocator customWebJarAssetLocator() {
    return new MyCustomSuperClassOfWebJarAssetLocator();
  }
  
  // override from WebMvcConfigurerAdapter
  @Override
  public WebJarsResourceResolver getWebJarsResourceResolver() {
    return new WebJarsResourceResolver(customWebJarAssetLocator());
  }

Most methods in WebMvcConfigurerAdapter return void, but some like
WebMvcConfigurerAdapter#getMessageCodesResolver() and WebMvcConfigurerAdapter#getValidator() already return instances.

Having said this I would still be thankful if the Brians proposal with the additional constructor would make it into 4.3

@spring-issuemaster
Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 30, 2016

Brian Clozel commented

For now, this use case is not very common as far as I know - and there are a couple of things to consider:

  1. WebMvcConfigurerAdapter is a first class citizen in the MVC space and developers like it because you can customize a lot and it is still (depending on your opinion) readable
  2. addResourceHandlers is quite visible already and you're not opting out of the whole @EnableWebMvc experience, which can be the case if you're trying to override one of the main MVC infrastructure beans
  3. WebJarAssetLocator is not part of Spring's classpath, so it's impossible to expose this in any "public" API without breaking things for many people

I understand how frustrating it is to opt out of Spring Boot's AutoConfiguration, but I don't see any other solution for this now. Maybe webjars-locator could provide some extension points/customizers for such cases?

@spring-issuemaster
Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Mar 31, 2016

Bartolom commented

Of course you have to keep the bigger picture in mind, and I only my use case. I would be happy to have your proposal with the additional constructor. Maybe one day WebJars usage in the Java community will grow, and one can adapt it later.

PS: It really nice to get rid of Bower in the build chain and use Java build tools

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
2 participants
You can’t perform that action at this time.