code: package com.taxonic.carml.rdf_mapper.impl;
  
  import com.google.common.collect.ImmutableSet;
  import com.taxonic.carml.rdf_mapper.PropertyHandler;
  import org.eclipse.rdf4j.model.Model;
  import org.eclipse.rdf4j.model.Resource;
  
  import java.lang.reflect.Method;
  import java.util.List;
  import java.util.Optional;
  import java.util.Set;
  import java.util.stream.Collectors;
  import java.util.stream.Stream;
  
  public class MethodPropertyHandlerRegistry {
  
      private Method method;
      private boolean isIterable;
      private Set<PropertyHandler> handlers;
  
      private MethodPropertyHandlerRegistry(Method method, boolean isIterable, Set<PropertyHandler> handlers) {
          this.method = method;
          this.isIterable = isIterable;
          this.handlers = handlers;
      }
  
      static Builder builder() {
          return new Builder();
      }
  
      static class Builder {
  
          private Method method;
          private Boolean isIterable;
          private ImmutableSet.Builder<PropertyHandler> handlersBuilder = new ImmutableSet.Builder<>() ;
  
          Builder method(Method method) {
              this.method = method;
              return this;
          }
  
          Builder isIterable(Boolean isIterable) {
              this.isIterable = isIterable;
              return this;
          }
  
          Builder addHandler(PropertyHandler handler) {
              handlersBuilder.add(handler);
              return this;
          }
  
          boolean isBuildable() {
              return isIterable != null;
          }
  
          MethodPropertyHandlerRegistry build() {
              if (method == null) {
                  throw new IllegalStateException("method cannot be null");
              }
              if (isIterable == null) {
                  throw new IllegalStateException("isIterable cannot be null");
              }
              return new MethodPropertyHandlerRegistry(method, isIterable.booleanValue(), handlersBuilder.build());
          }
      }
  
      Method getMethod() {
          return method;
      }
  
      Set<PropertyHandler> getHandlers() {
          return handlers;
      }
  
      Stream<Optional<PropertyHandler>> getEffectiveHandlers(Model model, Resource resource) {
          List<PropertyHandler> effectiveHandlers = handlers.stream()
                  .filter(h -> h.hasEffect(model, resource))
                  .collect(Collectors.toList());
  
          // Only apply one effective property handler for non-iterable property
          if (!isIterable) {
              return Stream.of(effectiveHandlers.stream().findFirst());
          }
  
          // for iterable property
          if(!effectiveHandlers.isEmpty()) {
              // if at least one effective handler, return all
              return effectiveHandlers.stream().map(Optional::ofNullable);
          } else {
              // if no effective handlers, return the first ineffective one for initialization of iterable type
              return Stream.of(handlers.stream().findFirst());
          }
      }
  
  }
  