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

WritableResource doesn't have parity with Resource in @Value etc. [SPR-10656] #15284

Closed
spring-projects-issues opened this issue Jun 15, 2013 · 8 comments
Assignees
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Milestone

Comments

@spring-projects-issues
Copy link
Collaborator

Dave Syer opened SPR-10656 and commented

Users can (and often do) inject Resource instances using placeholders and pattern matching, but this doesn't work with WritableResource. It might be an oversight?


Affects: 4.0 M1

1 votes, 4 watchers

@spring-projects-issues
Copy link
Collaborator Author

Phil Webb commented

Can you provide a small snippet of code to demonstrate what you mean?

@spring-projects-issues
Copy link
Collaborator Author

Dave Syer commented

This would fail to bind to the environment property:

@Component
public class MyWritingStuff {

@Value("${writing.file:file:/tmp/foo.txt}")
private WritableResource writable;

}

whereas this would succeed:

@Component
public class MyReadingStuff {

@Value("${writing.file:file:/tmp/foo.txt}")
private Resource writable;

}

@spring-projects-issues
Copy link
Collaborator Author

Phil Webb commented

I think I have a fix for this but it changes the default behavior of DefaultResourceLoader. Juergen Hoeller, could you review and let me know how risky you think this is?

#301

@spring-projects-issues
Copy link
Collaborator Author

Artem Bilan commented

Some our projects have started to bump to this issue, too: spring-attic/spring-cloud-gcp#72

Wouldn't it be great to revise the fix?

Thanks

@spring-projects-issues spring-projects-issues added status: waiting-for-triage An issue we've not yet triaged or decided on type: enhancement A general enhancement in: core Issues in core modules (aop, beans, core, context, expression) and removed type: enhancement A general enhancement labels Jan 11, 2019
@rstoyanchev rstoyanchev added status: bulk-closed An outdated, unresolved issue that's closed in bulk as part of a cleaning process and removed status: waiting-for-triage An issue we've not yet triaged or decided on labels Jan 11, 2019
@spring-projects-issues
Copy link
Collaborator Author

Bulk closing outdated, unresolved issues. Please, reopen if still relevant.

@fmbenhassine
Copy link
Contributor

Please, reopen if still relevant.

This issue is still relevant with SF 6.0.0 snapshots. Can you please take a look? This is actually blocking for spring-projects/spring-batch#756.

@jhoeller
Copy link
Contributor

jhoeller commented May 3, 2022

@benas are you specifically trying to inject an @Value WritableResource which isn't working out of the box? Can you confirm that @Value Resource with a subsequent downcast to WritableResource works (since we attempt to resolve a FileUrlResource there as of 5.0.2)? That would mean that we only have to add a ResourceEditor registration for WritableResource.

@jhoeller jhoeller reopened this May 3, 2022
@jhoeller jhoeller self-assigned this May 3, 2022
@jhoeller jhoeller added type: enhancement A general enhancement and removed status: bulk-closed An outdated, unresolved issue that's closed in bulk as part of a cleaning process labels May 3, 2022
@jhoeller jhoeller added this to the 5.3.20 milestone May 3, 2022
@fmbenhassine
Copy link
Contributor

Thank you for your feedback, Juergen.

are you specifically trying to inject an @Value WritableResource which isn't working out of the box?

Yes, I used the same sample as in this comment with the latest SF 6.0 snapshots. To give a bit of context, my specific use case is in Batch (issue spring-projects/spring-batch#756) where a change from Resource to WritableResource in AbstractFileItemWriter results in a failure to load this application context (The sample is in XML config, but I guess the configuration style should not matter). The sample fails with:

[main] ERROR org.springframework.batch.core.step.AbstractStep - Encountered an error executing step step1 in job ioSampleJob
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'scopedTarget.itemWriter' defined in class path resource [jobs/iosample/delimited.xml]: Initialization of bean failed; nested exception is org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'org.springframework.core.io.WritableResource' for property 'resource'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.core.io.WritableResource' for property 'resource': no matching editors or conversion strategy found
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:611)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:525)
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$1(AbstractBeanFactory.java:365)
	at org.springframework.batch.core.scope.StepScope.get(StepScope.java:113)
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:362)
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
	at org.springframework.aop.target.SimpleBeanTargetSource.getTarget(SimpleBeanTargetSource.java:35)
	at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:195)
	at jdk.proxy2/jdk.proxy2.$Proxy21.open(Unknown Source)
	at org.springframework.batch.item.support.CompositeItemStream.open(CompositeItemStream.java:131)
	at org.springframework.batch.core.step.tasklet.TaskletStep.open(TaskletStep.java:310)
	at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:216)
	at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:152)
	at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:68)
	at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:68)
	at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:170)
	at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:145)
	at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:137)
	at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:332)
	at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:149)
	at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
	at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:140)
	at org.springframework.batch.test.JobLauncherTestUtils.launchJob(JobLauncherTestUtils.java:156)
	at org.springframework.batch.sample.iosample.AbstractIoSampleTests.testUpdateCredit(AbstractIoSampleTests.java:72)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:74)
	at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:84)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
	at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
	at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
	at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
	at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: org.springframework.beans.ConversionNotSupportedException: Failed to convert property value of type 'java.lang.String' to required type 'org.springframework.core.io.WritableResource' for property 'resource'; nested exception is java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.core.io.WritableResource' for property 'resource': no matching editors or conversion strategy found
	at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:595)
	at org.springframework.beans.AbstractNestablePropertyAccessor.convertForProperty(AbstractNestablePropertyAccessor.java:609)
	at org.springframework.beans.BeanWrapperImpl.convertForProperty(BeanWrapperImpl.java:190)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.convertForProperty(AbstractAutowireCapableBeanFactory.java:1700)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1656)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1400)
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:602)
	... 54 more
Caused by: java.lang.IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.core.io.WritableResource' for property 'resource': no matching editors or conversion strategy found
	at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:262)
	at org.springframework.beans.AbstractNestablePropertyAccessor.convertIfNecessary(AbstractNestablePropertyAccessor.java:590)
	... 60 more

Can you confirm that @Value Resource with a subsequent downcast to WritableResource works (since we attempt to resolve a FileUrlResource there as of 5.0.2)?

I'm not sure if this is a regression or not, but the following snippet fails with a ClassCastException with the latest 6.0 snapshots:

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.WritableResource;
import org.springframework.stereotype.Component;

@Configuration
public class WritableResourceConversionSample {

    public static void main(String[] args) throws Exception {
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(WritableResourceConversionSample.class);
        MyService myService = applicationContext.getBean(MyService.class);
        myService.printMessage(); // fails with java.lang.ClassCastException: class org.springframework.core.io.DefaultResourceLoader$ClassPathContextResource cannot be cast to class org.springframework.core.io.WritableResource
    }

    @Component
    public static class MyService {

        @Value("${file:/tmp/myWritableFile.txt}")
        private Resource resource;// With a WritableResource here, the sample fails at startup with an IllegalStateException: Cannot convert value of type 'java.lang.String' to required type 'org.springframework.core.io.WritableResource': no matching editors or conversion strategy found

        public void printMessage() {
            System.out.println(((WritableResource) resource).isWritable());
        }
    }

}

Let me know if you need more details on this. Thank you upfront.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
in: core Issues in core modules (aop, beans, core, context, expression) type: enhancement A general enhancement
Projects
None yet
Development

No branches or pull requests

4 participants