paulcwarren / spring-content

Cloud-Native Storage and Enterprise Content Services (ECMS) for Spring
https://paulcwarren.github.io/spring-content/
Apache License 2.0
267 stars 65 forks source link

ContentStore bean #203

Open xLegna opened 4 years ago

xLegna commented 4 years ago

I have a question to use ContentStore.

package gettingstarted;

import org.springframework.content.commons.repository.ContentStore;

public interface FileContentStore extends ContentStore<File, String> {
}

To use my contentStore like this: @Autowired private FileContentStore contentsRepo;

This is my interface, should I add @Repository to the interface? Who should create the bean FileContentStore?

Vmarci94 commented 4 years ago

it interests me too. image This code is working, but not too nice.

paulcwarren commented 4 years ago

Hi @Vmarci94,

To use my contentStore like this:

@Autowired private FileContentStore contentsRepo;

Yes that is how you can autowire the content store into another part of your code in order to make use of it.

This is my interface, should I add @repository to the interface?

No, that is a Spring Data construct. Spring Content does not require this.

Who should create the bean FileContentStore?

Spring Content will create it for you. When your application starts Spring Content will see the FileContentStore and it will see spring-content-fs on your classpath and inject a proxy.

This code is working, but not too nice.

Not too nice because the IDE has underlined it?

Vmarci94 commented 4 years ago

Thank You the quick answer.

Sorry the "not too nice" expression. Rather a little confusing to my reviewers. They are very trusting in Intellij IDEA ...

Although You said, the @reposirtoy annotation is a Spring Data construct, and Spring Content does not required this, I added the @Component annotation and solved this little thing.

I would have another question. Although I don't think you'll be happy for him. So I want to set file names, because the directory is a remote drive and several others process use this files. I think this api not entirely for that.

I found DefaultFilesystemStoreImpl class and EnableFilesystemContentRepositories.storeFactoryBeanClass method, i thought write a customFilesystemStoreImpl, but i see the EnableFilesystemContentRepositories annotation is Deprecated. I would be interested in another solution. Do you think I can solve this?

paulcwarren commented 4 years ago

Although You said, the @reposirtoy annotation is a Spring Data construct, and Spring Content does not required this, I added the @component annotation and solved this little thing.

Ah I see what you are saying. This is an IDE thing then. Intellij, in this case, needs to know it is a bean otherwise it will flag it as an error. Although, in our case, spring content stores are bean and will be wired correctly. Just intellij doesn't know that. I will work on this. It would be fine to add a bean annotation on Store so developers don't have annotate their store interfaces directly.

I would have another question. Although I don't think you'll be happy for him. So I want to set file names, because the directory is a remote drive and several others process use this files. I think this api not entirely for that.

Each Store Module (except JPA) has a placement service that is responsible for locating the content in the backing store. This placement service can be configured through a standard Spring converter. It can be done in a couple of ways depending on requirements. Sounds like you know what you want to call the file so I would suggest something like this.

Assume you have a Document entity like this:

@Entity
@Data
public class Document {

    @Id
    @GeneratedValue(strategy=AUTO)
    private Long id;

    @ContentId
    private UUID contentId;

    @ContentLength
    private Long contentLength;

    @MimeType
    private String mimeType;

    private String contentPath;
}

Then you can add a configurer like this:

    @Configuration
    public static class StoreConfig {
        @Bean
        public FilesystemStoreConfigurer configurer() {
            return new FilesystemStoreConfigurer() {

                @Override
                public void configureFilesystemStoreConverters(ConverterRegistry registry) {
                    registry.addConverter(new Converter<Document, String>() {

                        @Override
                        public String convert(Document document) {
                            return document.getContentPath();
                        }
                    });
                }
            };
        }
    }

Now, when you set content for an instance of Document, the placement service will call the converter to establish where to store that contnet.

So, if you created a Document and set its contentPath to /some/path/my-file. Then your content will be stored in your backing store (remote share) at /some/path/my-file.

Would this solve your problem?

paulcwarren commented 4 years ago

I updated the docs for the filesystem module to (hopefully) explain this better: https://paulcwarren.github.io/spring-content/refs/snapshot/1.0.x/fs-index.html#_accessing_content

paulcwarren commented 4 years ago

I looked into the problem marker that you highlighted. I also see this BTW. And it is annoying. But I suspect that there are smarts in the spring plugins that make this work for Spring Data repositories.

We would need to add a similar plugin for Spring Content.

andye2004 commented 3 years ago

@paulcwarren, I only just saw this but there are no plugin changes required my friend. Simply add the internal.org.springframework.content package to the @ComponentScan and it should 'just work' E.g.

@SpringBootApplication
@ComponentScan(basePackages = "internal.org.springframework.content")
public class Application {
}

The issue with just using the plain @SpringBootApplication is that it will only include beans defined within the 'default' package (the package in which the Application class) is defined and it's sub-packages, as well as the Spring beans. Anything outside of these things has to be added to the @ComponentScan as a package using basePackages or as a class using basePackageClasses to be picked up.

FYI @xLegna, @Vmarci94

paulcwarren commented 3 years ago

Thanks for the info.

Yeah, I think what is weird for me about this is that you don't need this @ComponentScan application for the correct functioning of the application. intellij's error is in reality a false negative.

Eclipse for example, doesn't exhibit this behavior so (I'm assuming) the eclipse spring plugins generally solve this (on behalf of the developer) and intellij solves it for known spring projects but not others like this one.

We can definitely add this @ComponentScan to our spring boot starters as that will have no effect for eclipse developers but fix it for intellij developers. But this seems like a bug with the intellij spring problem markers to me.

andye2004 commented 3 years ago

Hey Paul, interesting point re eclipse, it must be scanning the entire runtime classpath for bean candidates. I know that the IntelliJ plugin generally doesn't do this and relies on configuration to determine where it resolves beans - I'm guessing this is for performance reasons.

I'm not sure adding @ComponentScan to the SB starters is going to resolve this issue as scanning for the project would still only be done for anything org.spring.... and anything under the default package. Would be good if it did work but my gut says it needs to be added to each project.

maksym-matlo commented 1 year ago

@paulcwarren I want to store java.sql.Blob with Spring Data. How to configure you dependency in this case and which exactly dependency do I have to use?

paulcwarren commented 1 year ago

@maksym-matlo the basic setup is described in the jpa guide here. And you might find the set of jpa integration tests a useful guide also. And lastly it should be pretty simple to adapt any of the getting started guides like the rest one. You would just need to swap out fs storage, for jpa storage.

mosup16 commented 1 year ago

@paulcwarren, I only just saw this but there are no plugin changes required my friend. Simply add the internal.org.springframework.content package to the @ComponentScan and it should 'just work' E.g.

@SpringBootApplication
@ComponentScan(basePackages = "internal.org.springframework.content")
public class Application {
}

The issue with just using the plain @SpringBootApplication is that it will only include beans defined within the 'default' package (the package in which the Application class) is defined and it's sub-packages, as well as the Spring beans. Anything outside of these things has to be added to the @ComponentScan as a package using basePackages or as a class using basePackageClasses to be picked up.

I tried this but I got Could not find class [internal.org.springframework.content.jpa.config.JpaStoreFactoryBean]