1 /* 2 * %injeqt copyright begin% 3 * Copyright 2014 Rafał Malinowski (rafal.przemyslaw.malinowski@gmail.com) 4 * %injeqt copyright end% 5 * 6 * This library is free software; you can redistribute it and/or 7 * modify it under the terms of the GNU Lesser General Public 8 * License as published by the Free Software Foundation; either 9 * version 2.1 of the License, or (at your option) any later version. 10 * 11 * This library is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * Lesser General Public License for more details. 15 * 16 * You should have received a copy of the GNU Lesser General Public 17 * License along with this library; if not, write to the Free Software 18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 19 */ 20 21 #pragma once 22 23 #include <injeqt/injeqt.h> 24 #include <injeqt/type.h> 25 26 #include <memory> 27 #include <vector> 28 #include <QtCore/QObject> 29 30 /** 31 * @file 32 * @brief Contains classes and functions for creating injectors. 33 */ 34 35 namespace injeqt { namespace internal { 36 class injector_impl; 37 }} 38 39 namespace injeqt { namespace v1 { 40 41 class module; 42 43 /** 44 * @brief Injector is created from set of modules that contains injectable types. 45 * 46 * Injector is constructed from set of modules that contains groups of related types. 47 * Then it can be used to get instances of configured types that have their dependencies 48 * resolved and set - there is no need to manually wire services and factories. 49 * 50 * If two or more modules have the same type configured an exception is thrown during construction. 51 * Otherwise, from all types in modules a set of available types is computed. Each type directly 52 * added to modules is added to it. Then all unique super types are added to this set. This means 53 * that two types with common ancestor can be used in injection. Note that Qt meta object system 54 * only supports single inheritance. 55 * 56 * Injector takes ownership of modules passed to it. Also all objects created inside injector 57 * (using default constructor - configured with module::add_type<T>(), or factory - configured 58 * with module::add_factory<T, F>()) are under its ownership. Lifetime of objects added as ready 59 * objects (configured with module::add_ready_object<T>(QObject *) is not managed by injector. 60 * For clarity ready objects can be stored in module instances as unique pointers. Injector will own 61 * then as it own modules. 62 */ 63 class INJEQT_API injector final 64 { 65 66 public: 67 /** 68 * @brief Create empty injector with no types configured. 69 * 70 * Empty injector will not be able to produce any object of any type. 71 */ 72 injector(); 73 74 /** 75 * @brief Create new injector from provided modules. 76 * @param modules list of modules 77 * @throw ambiguous_types if one or more types in @p modules is ambiguous 78 * @throw unresolvable_dependencies if a type with unresolvable dependency is found in @p modules 79 * @throw dependency_on_self when type depends on self 80 * @throw dependency_on_subtype when type depends on own supertype 81 * @throw dependency_on_subtype when type depends on own subtype 82 * @throw invalid_setter if any tagged setter has parameter that is not a QObject-derived pointer 83 * @throw invalid_setter if any tagged setter has parameter that is a QObject pointer 84 * @throw invalid_setter if any tagged setter has other number of parameters than one 85 * 86 * Creates injector with all types from modules configured. If combined configuration 87 * of all modules is invalid an exception is thrown. Configuration is invalid when: 88 * * any type is configured in more than one module 89 * * a dependency exists with type that is non configured in any module 90 * * a cycle of factories is found (currently does not throw an exception) 91 */ 92 explicit injector(std::vector<std::unique_ptr<module>> modules); 93 94 /** 95 * @brief Create new injector from provided modules with set of parent injectors. 96 * @param super_injectors list of injectors providing types for this one to use 97 * @param modules list of modules 98 * @throw ambiguous_types if one or more types in @p modules is ambiguous 99 * @throw unresolvable_dependencies if a type with unresolvable dependency is found in @p modules 100 * @throw dependency_on_self when type depends on self 101 * @throw dependency_on_subtype when type depends on own supertype 102 * @throw dependency_on_subtype when type depends on own subtype 103 * @throw invalid_setter if any tagged setter has parameter that is not a QObject-derived pointer 104 * @throw invalid_setter if any tagged setter has parameter that is a QObject pointer 105 * @throw invalid_setter if any tagged setter has other number of parameters than one 106 * 107 * Creates injector with all types from modules configured. Also a virtual module consisting of all 108 * provided types from @p super_injectors is added to module set. If combined configuration 109 * of all modules is invalid an exception is thrown. Configuration is invalid when: 110 * * any type is configured in more than one module 111 * * a dependency exists with type that is non configured in any module 112 * * a cycle of factories is found (currently does not throw an exception) 113 */ 114 explicit injector(std::vector<injector *> super_injectors, std::vector<std::unique_ptr<module>> modules); 115 116 injector(injector &&x); 117 ~injector(); 118 119 injector & operator = (injector &&x); 120 121 /** 122 * @brief Instantiates object of given type @tparam T 123 * @tparam T type of object to instantiate 124 * @throw unknown_type if @@tparam T was not configured in injector 125 * @throw instantiation_failed if instantiation of one of required types failed 126 * 127 * When object of given type is instantiated by instantiate<T>() method, injector first check if T is in set of 128 * available types. If not, an exception is thrown. Next an unique configured type U that implements T 129 * is found. If object of type U was already created, method returns. If not, it is created with all 130 * dependencies it requires. Depending on configuration of U it can be created directly by U default 131 * constructor or it can be created by factory that is assigned to that type (note: injector will 132 * create itself all required factories with the same alghoritm). After U with all its dependencies 133 * is created all dependency setters are called with proper arguments. Then U object is added to cache. 134 */ 135 template<typename T> instantiate()136 void instantiate() 137 { 138 instantiate(make_type<T>()); 139 } 140 141 /** 142 * @brief Returns pointer to object of given type T. 143 * @tparam T type of object to return 144 * @throw qobject_type if T is QObject 145 * @throw unknown_type if @p interface_type was not configured in injector 146 * @throw instantiation_failed if instantiation of one of required types failed 147 * 148 * When object of given type is requested by get<T>() method, injector first check if T is in set of 149 * available types. If not, an exception is thrown. Next an unique configured type U that implements T 150 * is found. If object of type U was already created, it is returned. If not, it is created with all 151 * dependencies it requires. Depending on configuration of U it can be created directly by U default 152 * constructor or it can be created by factory that is assigned to that type (note: injector will 153 * create itself all required factories with the same alghoritm). After U with all its dependencies 154 * is created all dependency setters are called with proper arguments. Then U object is added to cache 155 * and is itself returned. 156 */ 157 template<typename T> get()158 T * get() 159 { 160 return qobject_cast<T *>(get(make_type<T>())); 161 } 162 163 /** 164 * @brief Returns all objects with given @p type_role. 165 * @throw instantiation_failed if instantiation of one of found types failed 166 */ 167 std::vector<QObject *> get_all_with_type_role(const std::string &type_role); 168 169 /** 170 * @brief Instantiates object of given type @p interface_type 171 * @param interface_type type of object to return 172 * @throw empty_type if interface_type is empty 173 * @throw qobject_type if interface_type represents QObject 174 * @throw unknown_type if @p interface_type was not configured in injector 175 * @throw instantiation_failed if instantiation of one of required types failed 176 */ 177 void instantiate(const type &interface_type); 178 179 /** 180 * @brief Instantiate all objects with given @p type_role. 181 * @throw instantiation_failed if instantiation of one of found types failed 182 */ 183 void instantiate_all_with_type_role(const std::string &type_role); 184 185 /** 186 * @brief Returns pointer to object of given type interface_type. 187 * @param interface_type type of object to return 188 * @throw empty_type if interface_type is empty 189 * @throw qobject_type if interface_type represents QObject 190 * @throw unknown_type if @p interface_type was not configured in injector 191 * @throw instantiation_failed if instantiation of one of required types failed 192 * 193 * @see T * get<T>() 194 */ 195 QObject * get(const type &interface_type); 196 197 /** 198 * @brief Inject dependencies into @p object. 199 * @param object object to inject dependencies into. 200 * @throw invalid_setter if any tagged setter has parameter that is not a QObject-derived pointer 201 * @throw invalid_setter if any tagged setter has parameter that is a QObject pointer 202 * @throw invalid_setter if any tagged setter has parameter that is a QObject-derived pointer of not configured type 203 * @throw invalid_setter if any tagged setter has other number of parameters than one 204 * @pre object != nullptr 205 * 206 * This method looks for invokable setters tagged with INJEQT_SET in @p object. If any of setter is not valid 207 * dependency injector setter or its parameter is of type not configured in injector an exception is thrown. 208 * If all setters are valid, they are called with proper objects (which may be already available in injector 209 * or created on demand). 210 */ 211 void inject_into(QObject *object); 212 213 private: 214 std::unique_ptr<injeqt::internal::injector_impl> _pimpl; 215 216 }; 217 218 }} 219