Google Cloud Storage Add-On migration from Cuba 7.2 to Jmix 1.5

Hi:

I have a working implementation of Google Cloud Storage in my Cuba 7.2 application based on the AWS S3 code. I am migrating to Jmix 1.5, so I’m trying to convert my code into an add-on.

Since I have many documents already stored with File Descriptors in the database, I have to make sure that my new add-on is still compatible with Cuba file storage conventions - like the names of the directories/files, using File Descriptors instead of File Refs, etc.

Since Jmix now supports multiple file storage solutions and allows for choosing a default file storage via jmix.core.default-file-storage, I was thinking that it would be better to write a new add-on compatible with the new FileStorage system using FileRefs then configuring the CubaFileStorage compatiblity class to use it instead of LocalFileStorage:

@Component("cuba_FileStorage")
public class CubaFileStorage implements FileStorageAPI {
    @Autowired
    protected LocalFileStorage delegate;

Unfortunately, the CubaFileStorage class only uses LocalFileStorage. Is there a way to override this?

Thanks for all the help!

Eric

Does anybody have any advice? I’ve tried all kinds of things. For example, I have this in my addon:

@Component("gcsfs_Gcsfs")
public class Gcsfs extends CubaFileStorage implements FileStorageAPI {

And then I have this in my @SpringBootApplication main code:

    @Bean
    @Primary
    Gcsfs gcsfs() {
        return new Gcsfs();
    }

I’m trying to follow the recipe in the Overriding Spring Beans section of the documentation. The idea is that we should return my bean whenever CubaFileStorage is called, but it isn’t working.

I use this to display PDFs stored in GCS. It all worked fine in Cuba 7.2, but I just can’t seem to figure out how to get it to operate under Jmix 1.5. No matter what I do, the code ends up trying to access LocalFileStorage via the CubaFileStorage bean, which is hardcoded there.

@Component("cuba_FileStorage")
public class CubaFileStorage implements FileStorageAPI {
    @Autowired
    protected LocalFileStorage delegate;

It doesn’t even use the FileStorageLocator to pick one! This is why I’ve been trying to override CubaFileStorage with my own bean instead.

I see that it is possible to use the AWS file system add-on with GCS and do away with my own code completely, but that still won’t resolve the issue if CubaFileStorage only accesses LocalFileStorage.

Please help! :slight_smile:

Hello Eric,

CubaFileStorage is a CUBA-compatible proxy to Jmix LocalFileStorage, so there is a hardcoded delegate.

Looks like you need to update your CUBA-compatible FS (Gcsfs) implementation, override all methods which use LocalFileStorage delegate and replace those usages with your own delegate.

You can override existing CubaFileStorage the following way:

  • Remove “@Component” from Gcsfs
  • Create bean in @SpringBootApplication
    @Bean("cuba_FileStorage")
    @Primary
    CubaFileStorage gcsfs() {
        return new Gcsfs();
    }

Regards,
Ivan

OK, removing @Component is the trick. I’m still trying to understand when to use @Component vs @Bean.

I’m also thinking of just scrapping my bean entirely. Instead I will use your AWS add on and the Google Cloud Storage compatibility option. The only trick is translating FileDescriptors to FileRefs, but I can pull that code from your CubaFileStorage proxy.

You might consider making CubaFileStorage a proxy for all file storage setup, instead of hard coding LocalFileStorage. Then this might have worked out of the box.

Not sure if we’ll make such changes in cuba-compatibility module, but thanks anyway.

As for the @Component vs @Bean:
It’s not a trick but just two different ways of bean definition.

Actually, adding @Primary next to your @Component should also work (without @Bean method in app class).

In your example, when you use both ways you actually created 2 beans with the same code base (you can add log message to constructor):

  1. First created by @Component with type “Gcsfs” and qualifier “gcsfs_Gcsfs” (explicitly specified)
  2. Second created by @Bean with type “Gcsfs” and qualifier “gcsfs” (it uses method name if there is no explicitly specified qualifier).

I see. I did see two beans being created. Now I know why. Thanks.