ru.vyarus.java.generics.resolver.context.GenericsContext Java Examples

The following examples show how to use ru.vyarus.java.generics.resolver.context.GenericsContext. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: ConfigTreeBuilder.java    From dropwizard-guicey with MIT License 6 votes vote down vote up
/**
 * Cases:
 * <ul>
 * <li>Type declared in class and used as is: resolve generics directly from type</li>
 * <li>Type declared, but lower type used (e.g. collection impl declared): track lower type generics</li>
 * <li>Type is Object: resolve generics from declaration (lower type available when value provided)</li>
 * </ul>.
 *
 * @param genericsContext generics context
 * @param type            declared property type
 * @param typeClass       type's class
 * @param objectDeclared  declared type is not Object
 * @param lowerType       selected type from declaration (maybe lower then declared or comletely taken from value)
 * @return lower type generics or empty list
 */
private static List<Type> resolveLowerGenerics(final GenericsContext genericsContext,
                                               final Type type,
                                               final Class typeClass,
                                               final boolean objectDeclared,
                                               final Class lowerType) {
    final List<Type> res;
    if (!objectDeclared && !lowerType.equals(typeClass)) {
        // case: collection declared, but not interface.. going to lower type
        res = genericsContext.inlyingType(type).type(lowerType).genericTypes();
    } else {
        // normal case: type analyzed directly
        res = genericsContext.resolveTypeGenerics(objectDeclared ? lowerType : type);
    }
    return res;
}
 
Example #2
Source File: ConfigTreeBuilder.java    From dropwizard-guicey with MIT License 6 votes vote down vote up
/**
 * Cases:
 * <ul>
 * <li>Object declared in class: nowere to get generics, resolving from type definition</li>
 * <li>Track type generics from declared generics (may not recover all, in this case generics declaration
 * would be used)</li>
 * </ul>.
 * Note that lowerType == upperType case checked outside.
 *
 * @param genericsContext generics context
 * @param type            declared property type
 * @param objectDeclared  declared type is not Object
 * @param upperType       value type (if value available) or declaration type (from class; may be upper then
 *                        lowerType in case of collection)
 * @return upper type generics or empty list
 */
private static List<Type> resolveUpperGenerics(final GenericsContext genericsContext,
                                               final Type type,
                                               final boolean objectDeclared,
                                               final Class upperType) {
    final List<Type> res;
    if (objectDeclared) {
        // no generics declared in class - use raw generics (from type declaration)
        res = genericsContext.resolveTypeGenerics(upperType);
    } else {
        // computing from actual generic type because it may contain generics, not required for lower type
        // e.g. declaration is ExtraList<String, Integer>  lower type will be List<String>
        // but we need to preserve full generics info for upper type
        res = genericsContext.inlyingTypeAs(type, upperType).genericTypes();
    }
    return res;
}
 
Example #3
Source File: JerseyBinding.java    From dropwizard-guicey with MIT License 6 votes vote down vote up
/**
 * Binds jersey specific component (component implements jersey interface or extends class).
 * Specific binding is required for types directly supported by jersey (e.g. ExceptionMapper).
 * Such types must be bound to target interface directly, otherwise jersey would not be able to resolve them.
 * <p> If type is {@link JerseyManaged}, binds directly.
 * Otherwise, use guice "bridge" factory to lazily bind type.</p>
 *
 * @param binder        jersey binder
 * @param injector      guice injector
 * @param type          type which implements specific jersey interface or extends class
 * @param specificType  specific jersey type (interface or abstract class)
 * @param jerseyManaged true if bean must be managed by jersey, false to bind guice managed instance
 * @param singleton     true to force singleton scope
 */
public static void bindSpecificComponent(final AbstractBinder binder,
                                         final Injector injector,
                                         final Class<?> type,
                                         final Class<?> specificType,
                                         final boolean jerseyManaged,
                                         final boolean singleton) {
    // resolve generics of specific type
    final GenericsContext context = GenericsResolver.resolve(type).type(specificType);
    final List<Type> genericTypes = context.genericTypes();
    final Type[] generics = genericTypes.toArray(new Type[0]);
    final Type bindingType = generics.length > 0 ? new ParameterizedTypeImpl(specificType, generics)
            : specificType;
    if (jerseyManaged) {
        optionalSingleton(
                binder.bind(type).to(type).to(bindingType),
                singleton);
    } else {
        optionalSingleton(
                binder.bindFactory(new GuiceComponentFactory<>(injector, type)).to(type).to(bindingType),
                singleton);
    }
}
 
Example #4
Source File: TargetMethodAnalyzer.java    From guice-persist-orient with MIT License 6 votes vote down vote up
/**
 * Analyze target bean methods, finding all matching (by parameters) methods.
 * If method name was specified, only methods with the same name resolved.
 *
 * @param target target bean type
 * @param params repository method params
 * @param hint   method name hint (may be null)
 * @return descriptor of all matching methods
 */
private static List<MatchedMethod> findPossibleMethods(final List<Class<?>> params, final Class<?> target,
                                                       final String hint) {
    final List<MatchedMethod> possibilities = Lists.newArrayList();
    // use generics to enforce type checks
    final GenericsContext targetGenerics = GenericsResolver.resolve(target);
    for (Method method : target.getMethods()) {
        // method hint force to check only methods with this name
        final boolean methodHintValid = hint == null || method.getName().equals(hint);
        if (!isAcceptableMethod(method) || !methodHintValid) {
            continue;
        }
        final MatchedMethod matched = analyzeMethod(method, params, targetGenerics);
        if (matched != null) {
            possibilities.add(matched);
        }
    }
    return possibilities;
}
 
Example #5
Source File: TargetMethodAnalyzer.java    From guice-persist-orient with MIT License 6 votes vote down vote up
@SuppressWarnings({"unchecked", "PMD.AvoidInstantiatingObjectsInLoops"})
private static MatchedMethod analyzeMethod(final Method method, final List<Class<?>> params,
                                           final GenericsContext targetGenerics) {
    final List<ParamInfo> ordinalParamsInfo = Lists.newArrayList();
    final List<Class<?>> types = targetGenerics.method(method).resolveParameters();
    final Annotation[][] annotations = method.getParameterAnnotations();
    boolean extended = false;
    for (int i = 0; i < types.size(); i++) {
        // ignore extensions (they always add value)
        try {
            if (ExtUtils.findParameterExtension(annotations[i]) == null) {
                ordinalParamsInfo.add(new ParamInfo(i, types.get(i)));
            } else {
                extended = true;
            }
        } catch (Exception ex) {
            throw new IllegalStateException(String.format("Error analysing method %s parameter %s",
                    RepositoryUtils.methodToString(method), i), ex);
        }
    }
    MatchedMethod res = null;
    if (isParametersCompatible(params, ordinalParamsInfo)) {
        res = new MatchedMethod(method, ordinalParamsInfo, extended);
    }
    return res;
}
 
Example #6
Source File: GenericInfoUtils.java    From generics-resolver with MIT License 6 votes vote down vote up
/**
 * Type analysis in context of analyzed type. For example, resolution of field type class in context of
 * analyzed class (so we can correctly resolve it's generics).In essence, the only difference with usual type
 * resolution is known root generics.
 * <p>
 * The result is not intended to be cached as it's context-sensitive.
 *
 * @param context       generics context of containing class
 * @param type          type to analyze (important: this must be generified type and not raw class in
 *                      order to properly resolve generics)
 * @param ignoreClasses classes to exclude from hierarchy analysis
 * @return analyzed type generics info
 */
public static GenericsInfo create(
        final GenericsContext context, final Type type, final Class<?>... ignoreClasses) {
    // root generics are required only to properly solve type
    final Map<String, Type> rootGenerics = context.visibleGenericsMap();
    // first step: solve type to replace transitive generics with direct values
    final Type actual = GenericsUtils.resolveTypeVariables(type, rootGenerics);
    final Class<?> target = context.resolveClass(actual);

    LinkedHashMap<String, Type> generics = GenericsResolutionUtils.resolveGenerics(actual, rootGenerics);
    generics = GenericsResolutionUtils
            .fillOuterGenerics(actual, generics, context.getGenericsInfo().getTypesMap());
    return create(target, generics,
            // store possible owner types from parent context
            usePossiblyOwnerGenerics(target, context.getGenericsInfo()), ignoreClasses);
}
 
Example #7
Source File: ConfigTreeBuilder.java    From dropwizard-guicey with MIT License 5 votes vote down vote up
/**
 * Create item for property.
 * <p>
 * Almost always property declaration type is used as binding type (for future binding), but:
 * <ul>
 * <li>If property type is collection implementation, then collection interface used instead</li>
 * <li>If property is Object then type would be taken from value. This means binding type will be Object
 * when value null and actual type when value provided. Assuming this case will not happen (bad config).</li>
 * </ul>
 *
 * @param root            root property (containing), may be null for roots
 * @param prop            jackson property descriptor
 * @param value           property value, may be null
 * @param genericsContext generics context
 * @return path item object
 */
private static ConfigPath createItem(final ConfigPath root,
                                     final BeanPropertyDefinition prop,
                                     final Object value,
                                     final GenericsContext genericsContext) {
    // need generified type to resolve generics manually because jackson's generics resolution
    // couldn't handle all required cases
    final Type type = prop.getGetter() != null
            ? prop.getGetter().getAnnotated().getGenericReturnType()
            : prop.getField().getAnnotated().getGenericType();
    final Class typeClass = Primitives.wrap(genericsContext.resolveClass(type));

    // upper possible known type (for introspection): ideally type of actually used configuration value
    // note that even when value is null upper type could be different from lower type due to collection projection
    final Class upperType = value == null ? typeClass : value.getClass();
    final boolean customType = isCustomType(upperType);
    // either class declaration or value type (in both cases could be projected to collection interface)
    final boolean objectDeclared = Object.class.equals(typeClass);
    final Class lowerType = correctValueType(objectDeclared ? upperType : typeClass, customType);

    final List<Type> lowerGenerics =
            resolveLowerGenerics(genericsContext, type, typeClass, objectDeclared, lowerType);
    final List<Type> upperGenerics = lowerType.equals(upperType) ? lowerGenerics
            : resolveUpperGenerics(genericsContext, type, objectDeclared, upperType);

    return new ConfigPath(
            root,
            prop.getAccessor().getDeclaringClass(),
            lowerType,
            // as an example, enum constant type could lead to anonymous class
            upperType.isAnonymousClass() ? lowerType : upperType,
            lowerGenerics,
            upperGenerics,
            fullPath(root, prop),
            value,
            customType,
            objectDeclared);
}
 
Example #8
Source File: ElAnalyzer.java    From guice-persist-orient with MIT License 5 votes vote down vote up
/**
 * Analyze query string for variables.
 *
 * @param genericsContext generics context (set to the method owner type)
 * @param query           query string
 * @return descriptor object if variables found, null otherwise
 */
public static ElDescriptor analyzeQuery(final GenericsContext genericsContext, final String query) {
    final List<String> vars = ElUtils.findVars(query);
    ElDescriptor descriptor = null;
    if (!vars.isEmpty()) {
        descriptor = new ElDescriptor(vars);
        checkGenericVars(descriptor, genericsContext);
    }
    return descriptor;
}
 
Example #9
Source File: ElAnalyzer.java    From guice-persist-orient with MIT License 5 votes vote down vote up
private static void checkGenericVars(final ElDescriptor descriptor, final GenericsContext generics) {
    if (generics != null) {
        for (Map.Entry<String, Type> entry : generics.genericsMap().entrySet()) {
            final String key = entry.getKey();
            if (descriptor.vars.contains(key)) {
                // using just class name, because orient don't need package
                descriptor.directValues.put(key, generics.resolveClass(entry.getValue()).getSimpleName());
            }
        }
    }
}
 
Example #10
Source File: GenericsTrackingUtils.java    From generics-resolver with MIT License 5 votes vote down vote up
private static Type[] alignParametrizationArguments(final Class<?> exactActualType,
                                                    final Class<?> knownGenericType,
                                                    final ParameterizedType knownGeneric,
                                                    final LinkedHashMap<String, Type> knownGenerics) {

    final Type[] knownArguments;

    // if base types are equal we can match types in parametrization
    if (exactActualType.equals(knownGenericType)) {
        knownArguments = knownGeneric.getActualTypeArguments();
    } else {
        // known generic type is a subclass of resolved root type.. inception!
        // trying to track generics
        if (knownGenericType.isAssignableFrom(exactActualType)) {
            // Actual type is higher then declared in generic: need to analyze this mismatch
            // (again not known root generics and known generics in sub type)
            final LinkedHashMap<String, Type> sub = track(exactActualType, knownGenericType,
                    GenericsResolutionUtils.resolveGenerics(knownGeneric, knownGenerics));
            knownArguments = sub.values().toArray(new Type[0]);
        } else {
            // actual class, resolved in root class hierarchy is a subtype of known generic type
            // building hierarchy for known generic value class and look generics of required subclass
            final GenericsContext ctx = GenericsResolver.resolve(knownGenericType);
            knownArguments = GenericInfoUtils.create(ctx, knownGeneric)
                    .getTypeGenerics(exactActualType).values().toArray(new Type[0]);
        }
    }
    return knownArguments;
}
 
Example #11
Source File: ConfigTreeBuilder.java    From dropwizard-guicey with MIT License 4 votes vote down vote up
/**
 * Use jackson serialization api to extract all configuration values with paths from configuration object.
 * Always analyze types, even if actual branch is not present at all (null value) in order to always bind
 * nulls and avoid "Schrodinger's binding" case. In short, bindings should not depend on configuration values
 * (presence).
 * <p>
 * Still, bindings may vary: for example, bound implementations may differ (best example is dropwizard server type),
 * as a consequences, parsed type may be different and so different properties paths could be recognized.
 *
 * @param config  jackson serialization config
 * @param content currently parsed paths
 * @param type    analyzed part type
 * @param object  analyzed part instance (may be null)
 * @return all configuration paths values
 */
@SuppressWarnings("checkstyle:CyclomaticComplexity")
private static List<ConfigPath> resolvePaths(final SerializationConfig config,
                                             final ConfigPath root,
                                             final List<ConfigPath> content,
                                             final Class type,
                                             final Object object,
                                             final GenericsContext genericsContext) {
    final BasicBeanDescription description = config.introspect(
            config.constructType(type)
    );

    for (BeanPropertyDefinition prop : description.findProperties()) {
        // ignore write-only or groovy special property
        if (!prop.couldSerialize() || prop.getName().equals("metaClass")) {
            continue;
        }
        final Object value;
        // if configuration doesn't expect serialization and throws error on access
        // (like netflix dynamic properties) it should not break app startup
        try {
            value = readValue(prop.getAccessor(), object);
        } catch (Exception ex) {
            LOGGER.warn("Can't bind configuration path '{}' due to {}: {}. Enable debug logs to see "
                            + "complete stack trace or use @JsonIgnore on property getter.",
                    fullPath(root, prop), ex.getClass().getSimpleName(), ex.getMessage());
            LOGGER.debug("Complete error: ", ex);
            continue;
        }

        final ConfigPath item = createItem(root, prop, value, genericsContext);
        content.add(item);
        if (root != null) {
            root.getChildren().add(item);
        }

        if (item.isCustomType() && !detectRecursion(item)) {
            // build generics context for actual value type (if not null)
            final GenericsContext subContext = prop.getGetter() != null
                    ? genericsContext.method(prop.getGetter().getAnnotated()).returnTypeAs(item.getValueType())
                    : genericsContext.fieldTypeAs(prop.getField().getAnnotated(), item.getValueType());

            resolvePaths(config, item, content, item.getValueType(),
                    item.getValue(), subContext);
        }
    }
    if (root != null) {
        // simple properties goes up and composite objects go lower (both groups sorted alphabetically)
        root.getChildren().sort(Comparator.comparing(o -> (o.isCustomType() ? 'b' : 'a') + o.getPath()));
    }
    return content;
}
 
Example #12
Source File: GenericInfoUtils.java    From generics-resolver with MIT License 4 votes vote down vote up
/**
 * Type analysis in context of analyzed type with child class as target type. Case: we have interface
 * (or base type) with generic in class (as field or return type), but we need to analyze actual
 * instance type (from value). This method will analyze type from new root (where generics are unknown), but
 * will add known middle generics.
 * <p>
 * NOTE: some of the root generics could possibly be resolved if there are any traceable connectivity between
 * the root class and known middle generics. All possible (known) cases should be solved. For example,
 * {@code Root<K> extends Target<List<K>>} when we know {@code Target<Collection<String>>} then
 * K will be tracked as String.
 * <p>
 * In essence: root generics are partially resolved by tracking definition from known middle class.
 * Other root generics resolved as upper bound (the same as in usual type resolution case).
 * If middle type generic is not specified (and so resolved as Object) then known specific type used
 * (assuming root type would be used in place with known parametrization and so more specifi generic may be
 * counted).
 * <p>
 * The result is not intended to be cached as it's context-sensitive.
 *
 * @param context       generics context of containing class
 * @param type          type to analyze (important: this must be generified type and not raw class in
 *                      order to properly resolve generics)
 * @param asType        target child type (this class contain original type in hierarchy)
 * @param ignoreClasses classes to exclude from hierarchy analysis
 * @return analyzed type generics info
 */
public static GenericsInfo create(final GenericsContext context,
                                  final Type type,
                                  final Class<?> asType,
                                  final Class<?>... ignoreClasses) {
    // root generics are required only to properly solve type
    final Map<String, Type> rootGenerics = context.visibleGenericsMap();
    // first step: solve type to replace transitive generics with direct values
    final Type actual = GenericsUtils.resolveTypeVariables(type, rootGenerics);
    final Class<?> middleType = context.resolveClass(actual);
    if (!middleType.isAssignableFrom(asType)) {
        throw new IllegalArgumentException(String.format("Requested type %s is not a subtype of %s",
                TypeToStringUtils.toStringType(asType), TypeToStringUtils.toStringType(middleType)));
    }

    // known middle type
    LinkedHashMap<String, Type> typeGenerics = GenericsResolutionUtils.resolveGenerics(actual, rootGenerics);
    final Map<Class<?>, LinkedHashMap<String, Type>> knownGenerics =
            new HashMap<Class<?>, LinkedHashMap<String, Type>>();
    // field could be declared as (Outer<String>.Inner field) and already contain actual outer generics
    knownGenerics.put(middleType, GenericsResolutionUtils
            .fillOuterGenerics(actual, typeGenerics, context.getGenericsInfo().getTypesMap()));
    if (TypeUtils.isInner(middleType)) {
        // remember possibly specified outer generics (they were already resolved above)
        knownGenerics.put((Class) TypeUtils.getOuter(middleType), new LinkedHashMap<String, Type>(
                GenericsUtils.extractOwnerGenerics(middleType, knownGenerics.get(middleType))));
    } else {
        // store other types for possible outer classes generics resolution
        knownGenerics.putAll(usePossiblyOwnerGenerics(asType, context.getGenericsInfo()));
    }


    // root type
    typeGenerics = asType.getTypeParameters().length > 0
            ? GenericsTrackingUtils.track(asType, middleType, typeGenerics)
            : EmptyGenericsMap.getInstance();

    typeGenerics = GenericsResolutionUtils
            .fillOuterGenerics(asType, typeGenerics, knownGenerics.size() > 1
                    // if known middle type is inner class then owner already filled
                    ? knownGenerics : context.getGenericsInfo().getTypesMap());
    return create(asType, typeGenerics, knownGenerics, ignoreClasses);
}
 
Example #13
Source File: GenericsResolver.java    From generics-resolver with MIT License 2 votes vote down vote up
/**
 * By default returned context set on root class (but generic types for root class will be resolved from specified
 * generics bounds). To use it switch context to required type from hierarchy:
 * {@code returnedContext.type(SomeTypeFromHierarchy.class)}.
 * <p>
 * Note: when ignore classes provided, produced {@code GenericsInfo} instance will not be cached
 * (and full version from cache will not be used also)
 *
 * @param type          root class to resolve generics hierarchy
 * @param ignoreClasses list of classes to ignore during inspection (useful to avoid interface clashes
 *                      or to limit resolution depth)
 * @return resolved generics context object
 */
public static GenericsContext resolve(final Class<?> type, final Class<?>... ignoreClasses) {
    final Class<?> notPrimitiveType = TypeUtils.wrapPrimitive(type);
    return new GenericsContext(
            GenericsInfoFactory.create(notPrimitiveType, ignoreClasses), notPrimitiveType);
}