All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.querydsl.codegen.AbstractModule Maven / Gradle / Ivy

/*
 * Copyright 2015, The Querydsl Team (http://www.querydsl.com/team)
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.querydsl.codegen;

import jakarta.inject.Inject;
import jakarta.inject.Named;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;
import java.util.Map;
import java.util.ServiceLoader;

/**
 * {@code AbstractModule} provides a base class for annotation based dependency injection
 *
 * @author tiwe
 */
public abstract class AbstractModule {

  private final Map, Object> instances = new HashMap<>();

  private final Map, Class> bindings = new HashMap<>();

  private final Map namedInstances = new HashMap<>();

  private final Map> namedBindings = new HashMap<>();

  public AbstractModule() {
    configure();
  }

  public final  AbstractModule bind(Class clazz) {
    if (clazz.isInterface()) {
      throw new IllegalArgumentException("Interfaces can't be instantiated");
    }
    bind(clazz, clazz);
    return this;
  }

  public final  AbstractModule bind(String name, Class implementation) {
    namedBindings.put(name, implementation);
    return this;
  }

  public final  AbstractModule bind(String name, T implementation) {
    namedInstances.put(name, implementation);
    return this;
  }

  public final  AbstractModule bindInstance(String name, Class implementation) {
    namedInstances.put(name, implementation);
    return this;
  }

  public final  AbstractModule bind(Class iface, Class implementation) {
    bindings.put(iface, implementation);
    return this;
  }

  public final  AbstractModule bind(Class iface, T implementation) {
    instances.put(iface, implementation);
    return this;
  }

  public final void loadExtensions() {
    ServiceLoader loader =
        ServiceLoader.load(Extension.class, Extension.class.getClassLoader());

    for (Extension extension : loader) {
      extension.addSupport(this);
    }
  }

  protected abstract void configure();

  @SuppressWarnings("unchecked")
  public final  T get(Class iface) {
    if (instances.containsKey(iface)) {
      return (T) instances.get(iface);
    } else if (bindings.containsKey(iface)) {
      Class implementation = bindings.get(iface);
      var instance = (T) createInstance(implementation);
      instances.put(iface, instance);
      return instance;
    } else {
      throw new IllegalArgumentException(iface.getName() + " is not registered");
    }
  }

  @SuppressWarnings("unchecked")
  public final  T get(Class iface, String name) {
    if (namedInstances.containsKey(name)) {
      return (T) namedInstances.get(name);
    } else if (namedBindings.containsKey(name)) {
      Class implementation = namedBindings.get(name);
      if (implementation != null) {
        var instance = (T) createInstance(implementation);
        namedInstances.put(name, instance);
        return instance;
      } else {
        return null;
      }
    } else {
      throw new IllegalArgumentException(iface.getName() + " " + name + " is not registered");
    }
  }

  @SuppressWarnings("unchecked")
  private  T createInstance(Class implementation) {
    Constructor constructor = null;
    for (Constructor c : implementation.getConstructors()) {
      if (c.isAnnotationPresent(Inject.class)) {
        constructor = c;
        break;
      }
    }

    // fallback to default constructor
    if (constructor == null) {
      try {
        constructor = implementation.getConstructor();
      } catch (SecurityException | NoSuchMethodException e) {
        throw new RuntimeException(e);
      }
    }

    if (constructor != null) {
      var args = new Object[constructor.getParameterTypes().length];
      for (var i = 0; i < constructor.getParameterTypes().length; i++) {
        var named = getNamedAnnotation(constructor.getParameterAnnotations()[i]);
        if (named != null) {
          args[i] = get(constructor.getParameterTypes()[i], named.value());
        } else {
          args[i] = get(constructor.getParameterTypes()[i]);
        }
      }
      try {
        return (T) constructor.newInstance(args);
        // TODO : populate fields as well?!?
      } catch (InstantiationException | InvocationTargetException | IllegalAccessException e) {
        throw new RuntimeException(e);
      }

    } else {
      throw new IllegalArgumentException(
          "Got no annotated constructor for " + implementation.getName());
    }
  }

  private Named getNamedAnnotation(Annotation[] annotations) {
    for (Annotation annotation : annotations) {
      if (annotation.annotationType().equals(Named.class)) {
        return (Named) annotation;
      }
    }
    return null;
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy