/** * Register a constructor key with a defined {@link Creator}. The key * defines the interface and parameters of the creation and the creator * actually creates the object. * * <pre>{@code * // import static org.openscience.cdk.DynamicFactory.key; * factory.register(key(IBond.class, IAtom[].class), * new BasicCreator<IAtom>(null) { * public IAtom create(Object[] objects) { * return new Bond((IAtom[]) objects); * } * }); * }</pre> * * @param key construction key, defines interface and parameter types * @param creator creates the actual object * @param <T> type of object that will be created * @return the registered creator - null if not registered */ public <T> Creator<T> register(ConstructorKey key, Creator<T> creator) { if (creator == null) return null; // make sure we don't register a constructor over an existing key if (cache.containsKey(key)) throw new IllegalArgumentException("cannot register " + key + " suppressed " + cache.get(key)); lookup.put(key.intf(), key); cache.put(key, creator); return creator; }
/** * Add a key for a given interface. * * @param intf an interface * @param key the key to add for the interface */ public void put(Class<?> intf, ConstructorKey key) { if (!keys.containsKey(intf)) { keys.put(intf, new HashMap<Integer, Set<ConstructorKey>>()); } Map<Integer, Set<ConstructorKey>> map = keys.get(intf); int n = key.n(); if (!map.containsKey(n)) { map.put(n, new HashSet<ConstructorKey>(5)); // few constructors per class } map.get(n).add(key); }
/** *{@inheritDoc} */ @Override public String toString() { StringBuilder sb = new StringBuilder(n() * 50); sb.append(intf().getSimpleName()); sb.append('('); int max = n() - 1; for (int i = 0; i <= max; i++) { sb.append(type(i).getSimpleName()); if (i != max) sb.append(", "); } sb.append(')'); return sb.toString(); }
if (key.isAssignable(candidate)) { return get(candidate); if (key.isUniform()) { Object types = Array.newInstance(key.type(0), 0); final ConstructorKey alt = new ObjectBasedKey(key.intf(), new Object[]{types});
if (key.isAssignable(candidate)) { return get(candidate); if (key.isUniform()) { Object types = Array.newInstance(key.type(0), 0); final ConstructorKey alt = new ObjectBasedKey(key.intf(), new Object[]{types});
/** * Register a constructor key with a defined {@link Creator}. The key * defines the interface and parameters of the creation and the creator * actually creates the object. * * <pre>{@code * // import static org.openscience.cdk.DynamicFactory.key; * factory.register(key(IBond.class, IAtom[].class), * new BasicCreator<IAtom>(null) { * public IAtom create(Object[] objects) { * return new Bond((IAtom[]) objects); * } * }); * }</pre> * * @param key construction key, defines interface and parameter types * @param creator creates the actual object * @param <T> type of object that will be created * @return the registered creator - null if not registered */ public <T> Creator<T> register(ConstructorKey key, Creator<T> creator) { if (creator == null) return null; // make sure we don't register a constructor over an existing key if (cache.containsKey(key)) throw new IllegalArgumentException("cannot register " + key + " suppressed " + cache.get(key)); lookup.put(key.intf(), key); cache.put(key, creator); return creator; }
/** * Provides a message for use with exceptions when no valid constructor is * found. The message is built using the suggestions from {@link * #suggest(Class)}. * * @param key the constructor key to build the message for * @return a message listing possible constructors */ private String getSuggestionMessage(ConstructorKey key) { StringBuilder sb = new StringBuilder(200); sb.append("No constructor found for '").append(key); sb.append("' candidates are: "); Iterator<ConstructorKey> iterator = suggest(key.intf()); while (iterator.hasNext()) { sb.append(iterator.next()); if (iterator.hasNext()) { sb.append(", "); } } return sb.toString(); }
/** * Provides a message for use with exceptions when no valid constructor is * found. The message is built using the suggestions from {@link * #suggest(Class)}. * * @param key the constructor key to build the message for * @return a message listing possible constructors */ private String getSuggestionMessage(ConstructorKey key) { StringBuilder sb = new StringBuilder(200); sb.append("No constructor found for '").append(key); sb.append("' candidates are: "); Iterator<ConstructorKey> iterator = suggest(key.intf()); while (iterator.hasNext()) { sb.append(iterator.next()); if (iterator.hasNext()) { sb.append(", "); } } return sb.toString(); }
/** * Indicates whether this key has multiple parameters and they are of * uniform type. If there are less then two types this method will * return false. {@code new Object[]{ Atom, Bond, Atom } } // false * {@code new Object[]{ Atom, Atom, Atom } } // true * * @return whether the key is uniform */ public boolean isUniform() { if (n() < 2) return false; Class<?> base = type(0); for (int i = 1; i < n(); i++) { if (type(i) != base) { return false; } } return true; }
/** * Orders constructor keys by the number of parameters and then this * name. * * @param o another constructor key * @return whether the other key is greater than, less than or equal to * this key */ @Override public int compareTo(ConstructorKey o) { // order by number of params first if (n() != o.n()) { return n() > o.n() ? 1 : n() < o.n() ? -1 : 0; } // use the lexicographic order of the toString method return toString().compareTo(o.toString()); }
/** * Add a key for a given interface. * * @param intf an interface * @param key the key to add for the interface */ public void put(Class<?> intf, ConstructorKey key) { if (!keys.containsKey(intf)) { keys.put(intf, new HashMap<Integer, Set<ConstructorKey>>()); } Map<Integer, Set<ConstructorKey>> map = keys.get(intf); int n = key.n(); if (!map.containsKey(n)) { map.put(n, new HashSet<ConstructorKey>(5)); // few constructors per class } map.get(n).add(key); }
/** * Indicates whether this key has multiple parameters and they are of * uniform type. If there are less then two types this method will * return false. {@code new Object[]{ Atom, Bond, Atom } } // false * {@code new Object[]{ Atom, Atom, Atom } } // true * * @return whether the key is uniform */ public boolean isUniform() { if (n() < 2) return false; Class<?> base = type(0); for (int i = 1; i < n(); i++) { if (type(i) != base) { return false; } } return true; }
/** * Orders constructor keys by the number of parameters and then this * name. * * @param o another constructor key * @return whether the other key is greater than, less than or equal to * this key */ @Override public int compareTo(ConstructorKey o) { // order by number of params first if (n() != o.n()) { return n() > o.n() ? 1 : n() < o.n() ? -1 : 0; } // use the lexicographic order of the toString method return toString().compareTo(o.toString()); }
/** * Checks whether this key is assignable to the candidate. * * @param candidate another constructor key * @return whether the provided candidate is assignable */ public boolean isAssignable(ConstructorKey candidate) { for (int i = 0; i < candidate.n(); i++) { // check whether the parameters are assignable if (!candidate.type(i).isAssignableFrom(type(i))) { return false; } } // no conflicts this constructor is okay return true; }
/** *{@inheritDoc} */ @Override public String toString() { StringBuilder sb = new StringBuilder(n() * 50); sb.append(intf().getSimpleName()); sb.append('('); int max = n() - 1; for (int i = 0; i <= max; i++) { sb.append(type(i).getSimpleName()); if (i != max) sb.append(", "); } sb.append(')'); return sb.toString(); }
/** * Checks whether this key is assignable to the candidate. * * @param candidate another constructor key * @return whether the provided candidate is assignable */ public boolean isAssignable(ConstructorKey candidate) { for (int i = 0; i < candidate.n(); i++) { // check whether the parameters are assignable if (!candidate.type(i).isAssignableFrom(type(i))) { return false; } } // no conflicts this constructor is okay return true; }
/** *{@inheritDoc} */ @Override public boolean equals(Object o) { if (o == null || !(o instanceof ConstructorKey)) return false; ConstructorKey that = (ConstructorKey) o; if (intf() != that.intf() || n() != that.n()) { return false; } for (int i = 0; i < n(); i++) { if (!type(i).equals(that.type(i))) return false; } return true; }
/** *{@inheritDoc} */ @Override public boolean equals(Object o) { if (o == null || !(o instanceof ConstructorKey)) return false; ConstructorKey that = (ConstructorKey) o; if (intf() != that.intf() || n() != that.n()) { return false; } for (int i = 0; i < n(); i++) { if (!type(i).equals(that.type(i))) return false; } return true; }
/** * Ensures primitive types are converted. */ @Test public void testKey_Primitives() { DynamicFactory.ConstructorKey key = DynamicFactory.key(IAtom.class, boolean.class, byte.class, char.class, short.class, int.class, float.class, long.class, double.class); assertEquals(IAtom.class, key.intf()); assertEquals(8, key.n()); assertEquals(Boolean.class, key.type(0)); assertEquals(Byte.class, key.type(1)); assertEquals(Character.class, key.type(2)); assertEquals(Short.class, key.type(3)); assertEquals(Integer.class, key.type(4)); assertEquals(Float.class, key.type(5)); assertEquals(Long.class, key.type(6)); assertEquals(Double.class, key.type(7)); }