Image component from (external) URL

We tried to implement (backoffice) screens with entity properties representing an image which is not hosted by the Jmix application (e.g. an avatar image of a user).

Unfortunately ImageImpl does not cover resource objects of the types java.net.URL or java.net.URI. So I implemented an extension of ImageImpl which is not a big deal:

public class ExtImageImpl<V> extends ImageImpl<V>
{
    //...

    @Nullable
    @Override
    protected Resource createImageResource(@Nullable final Object aResourceObject)
    {
        final Resource result;
        if (aResourceObject instanceof URL)
        {
            final URL url = (URL) aResourceObject;

            final UrlResource urlResource = new UrlResourceImpl();
            urlResource.setUrl(url);

            result = urlResource;
        }
        else if (aResourceObject instanceof URI)
        {
            final URI url = (URI) aResourceObject;

            UrlResource urlResource;
            try
            {
                urlResource = new UrlResourceImpl();
                urlResource.setUrl(url.toURL());
            }
            catch (final MalformedURLException ex)
            {
                urlResource = null;
                if (LOGGER.isDebugEnabled())
                {
                    // should never happen
                    LOGGER.debug(String.format("Could not create image resource from malformed URL: %s. %s", url,
                                    ex.getLocalizedMessage()), ex);
                }
            }

            result = urlResource;
        }
        else
        {
            result = super.createImageResource(aResourceObject);
        }

        return result;
    }
}

But using this implementation seemed to be tough. The only way which worked so far is pretty hacky:

@Subscribe
protected void onInit(final InitEvent anEvent)
{
    usersTable.addGeneratedColumn("avatar", entity -> {
        /*
         * uiComponents.create(ExtImageImpl.class)
         * Does not help because it's simple ignored and the standard implementation is created.
         * So we create the instance ourselves and post-process the creation it manually.
         */
        final Image<FileRef> image = new ExtImageImpl<>();
        UiComponentUtils.processApplicationContext(image, getApplicationContext());
        image.setValueSource(new ContainerValueSource<>(usersTable.getInstanceContainer(entity), "avatar"));

        return image;
    });
}

In UiComponentUtils we copied some code from UiComponentsImpl. Of course, that is not a sustainable approach.

  1. Is there a clean/proper way to implement own components?
  2. I there a reason for not supporting image components with non-application URLs?

Hi,
Have you tried using Image.setSource(UrlResource.class).setUrl(...) ?
See code sample and information in the docs:
https://docs.jmix.io/jmix/backoffice-ui/vcl/components/image.html#resource-types

1 Like

@albudarov No, we did not - but I did right now. This makes creating an own component obsolete.

Let me tell, why we tried this at all:

Not in the browse screen (I don’t know how to add a table column with an image component) but in the detail screen, we defined an image component with the image URL property of type java.net.URI as property attribute: <image id="userAvatarComp" property="avatar"/>

This causes an exception:
io.jmix.ui.GuiDevelopmentException: The Image component does not support property value binding for the property of type: java.net.URI, frameId=…
at io.jmix.ui.component.impl.ImageImpl.createImageResource(ImageImpl.java:144)
at io.jmix.ui.component.impl.ImageImpl.updateComponent(ImageImpl.java:120)
at io.jmix.ui.component.impl.ImageImpl.lambda$bindValueSourceEvents$1(ImageImpl.java:108)

That’s the reason for our approach, to add some more type support on ImageImpl.createImageResource(Object).

Your suggestion makes creating a custom component and it’s hacky use obsolete. Thank you so far.

But still I have to convert the java.net.URI entity attribute into an java.net.URL including handling the (to be) handled java.net.MalformedURLException before setting the UrlResouce.

Maybe this could be improved a little more?

@bank thanks for the feedback!
Created issue:

1 Like