X-Git-Url: http://wamblee.org/gitweb/?a=blobdiff_plain;f=system%2Fgeneral%2Fsrc%2Fmain%2Fjava%2Forg%2Fwamblee%2Fsystem%2Fadapters%2FConstructorConfiguration.java;fp=system%2Fgeneral%2Fsrc%2Fmain%2Fjava%2Forg%2Fwamblee%2Fsystem%2Fadapters%2FConstructorConfiguration.java;h=2725d0338fcae9026cf8f02754da8c2e5453f6f8;hb=7273d083a2f03cd3d2061d3c6628a46b679e718b;hp=0000000000000000000000000000000000000000;hpb=54b3f906ff4cb24e0deb3714a1c31a832abe1b5d;p=utils diff --git a/system/general/src/main/java/org/wamblee/system/adapters/ConstructorConfiguration.java b/system/general/src/main/java/org/wamblee/system/adapters/ConstructorConfiguration.java new file mode 100644 index 00000000..2725d033 --- /dev/null +++ b/system/general/src/main/java/org/wamblee/system/adapters/ConstructorConfiguration.java @@ -0,0 +1,165 @@ +/* + * Copyright 2008 the original author or authors. + * + * 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 org.wamblee.system.adapters; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Member; +import java.lang.reflect.Modifier; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.wamblee.collections.CollectionFilter; +import org.wamblee.conditions.Condition; +import org.wamblee.system.core.RequiredInterface; +import org.wamblee.system.core.Scope; +import org.wamblee.system.core.SystemAssemblyException; + +public class ConstructorConfiguration { + private Class _class; + private Constructor _constructor; + private ParameterValues _values; + private boolean _publicOnly; + + /** + * Constructs the configuration. By default no constructor is selected and + * one of {@link #select(Class...)} or + * {@link #greedy()} must be called. + * @param aClass Class to construct. + */ + public ConstructorConfiguration(Class aClass) { + _class = aClass; + _constructor = null; + _publicOnly = true; + } + + /** + * Sets whether or no non public constructors are also considered. + * Reset the choice of a constructor. + * @param aNonPublic + * @return + */ + public ConstructorConfiguration setNonPublic(boolean aNonPublic) { + _publicOnly = !aNonPublic; + _constructor = null; + _values = null; + return this; + } + + /** + * Selects an explicit constructor. + * @param aTypes Arguments of the constructor. + * @return Return the injector to allow call chaining. + */ + public ConstructorConfiguration select(Class... aTypes) { + try { + _constructor = _class.getDeclaredConstructor(aTypes); + } catch (Exception e) { + throw new SystemAssemblyException(e.getMessage(), e); + } + resetValues(); + return this; + } + + /** + * Selects the greediest constructor. + * @return The injector to allow call chaining. + * @throws SystemAssemblyException if the greediest constructor cannot be uniquely + * identified. + */ + public ConstructorConfiguration greedy() { + Constructor[] declared = _class.getDeclaredConstructors(); + if (declared.length == 0) { + throw new SystemAssemblyException("Class '" + _class + + " is an interface, primitive type, or array"); + } + int max = -1; + List> checked = new ArrayList>(); + CollectionFilter.filter(Arrays.asList(declared), checked, + new Condition>() { + @Override + public boolean matches(Constructor aObject) { + if ( !_publicOnly ) { + return true; + } else { + return Modifier.isPublic(aObject.getModifiers()); + } + } + }); + for (Constructor ctor : checked) { + if (ctor.getParameterTypes().length > max) { + max = ctor.getParameterTypes().length; + } + } + final int max2 = max; + List> ctors = checked; + List> longest = new ArrayList>(); + CollectionFilter.filter(ctors, longest, + new Condition>() { + @Override + public boolean matches(Constructor aObject) { + return aObject.getParameterTypes().length == max2; + } + }); + if (longest.size() > 1) { + throw new SystemAssemblyException( + "Greediest constructor cannot be uniquely determined"); + } + _constructor = longest.get(0); + resetValues(); + return this; + } + + public ParameterValues getParameters() { + getConstructor(); // initialize constructor if needed. + return _values; + } + + /** + * Resets the values. + */ + private void resetValues() { + _constructor.setAccessible(true); + _values = new ParameterValues(_constructor.getParameterTypes()); + } + + /** + * Creates the object in the given scope. + * @param aScope Scope containing required interfaces for this object. + * @return object. + */ + public Object create(Scope aScope) { + Object[] values = _values.values(aScope); + try { + return getConstructor().newInstance(values); + } catch (Exception e) { + throw new SystemAssemblyException("Could not construct object " + + getConstructor() + " " + Arrays.asList(values), e); + } + } + + public List getRequiredInterfaces() { + getConstructor(); // initialize constructor if needed. + return _values.getRequiredInterfaces(); + } + + private Constructor getConstructor() { + if (_constructor == null ) { + greedy(); + } + return _constructor; + } +}