class ResourceReferenceConverter {

    @SuppressWarnings("unchecked")
    public T toClient(ResourceReference serverObject, ToClientConversionOptions options) throws ClassCastException {
        ClientUriHolder result = null;
        if (serverObject != null) {
            if (options != null && options.isExpansionEnabled(serverObject.isLocal())) {
                try {
                    Resource localResource;
                    if (serverObject.isLocal()) {
                        localResource = serverObject.getLocalResource();
                    } else {
                        localResource = repositoryService.getResource(getRestrictedRuntimeExecutionContext(),
                                serverObject.getReferenceURI());
                    }

                    String clientType = resourceConverterProvider.getToClientConverter(localResource).getClientResourceType();
                    // Some repository resources, like Domain can have multiple client representations(for Domain there are
                    // semanticLayerDataSource and domain client types). In expansion by type client can declare required
                    // representation type. So, the idea of this part of code try to find client converter, that matches
                    // pair (target resource server type) - (expand client type).
                    if (options.isExpansionByType(serverObject.isLocal())) {
                        clientType = options.getExpandTypes().stream().filter(((expandClientType) ->
                                isClientConverterExist(localResource.getResourceType(), expandClientType)))
                               .findFirst().orElse(clientType);
                    }

                    if (options.isExpanded(clientType, serverObject.isLocal())) {
                        result = resourceConverterProvider.
                                getToClientConverter(localResource.getResourceType(), clientType)
                                .toClient(localResource, options);
                    } else {
                        result = new ClientReference(serverObject.getTargetURI());
                    }
                } catch (AccessDeniedException e) {
                    result = new ClientReference(serverObject.getTargetURI());
                }
            } else {
                result = new ClientReference(serverObject.getTargetURI());
            }
        }
        return (T) result;
    }

    public  ResourceReferenceConverter(ResourceConverterProvider resourceConverterProvider,
            RepositoryService repositoryService, PermissionsService permissionsService, RepositoryConfiguration configuration, ClientReferenceRestriction... restriction);

}