public static <T> T configure(PlcConfiguration configuration, T obj) {
        // Check if in this object is configurable at all.
        if (ClassUtils.isAssignable(obj.getClass(), HasConfiguration.class)) {
            // Check if the type declared by the HasConfiguration interface is
            // compatible with the given configuration type.
            Optional<ParameterizedType> typeOptional = Arrays.stream(obj.getClass().getGenericInterfaces())
                // Check if the interface has a type parameter
                .filter(ParameterizedType.class::isInstance)
                .map(ParameterizedType.class::cast)
                .filter(type -> type.getRawType().equals(HasConfiguration.class))
                .findAny();
            if (typeOptional.isPresent()) {
                final ParameterizedType parameterizedType = typeOptional.get();
                final Type configType = parameterizedType.getActualTypeArguments()[0];
                if (configType instanceof Class) {
                    Class<?> configClass = (Class<?>) configType;
                    if (configClass.isAssignableFrom(configuration.getClass())) {
                        try {
                            ((HasConfiguration) obj).setConfiguration(configuration);
                        } catch (Throwable t) {
                            LOGGER.error("Error setting the configuration", t);
                            throw new PlcRuntimeException("Error setting the configuration", t);
                        }
                    }
                }
            }

        }
        return obj;
    }
A query contains for our cases mostly of three parts
- protocol identifier
- (optional) transport identifier
- connection address (ip/port), serial port, path (depending on the type of transport) ...
- (optional) path parameters
plc4j/spi/src/main/java/org/apache/plc4x/java/spi/configuration/ConfigurationFactory.java