Search in sources :

Example 1 with ReflectException

use of org.jooq.tools.reflect.ReflectException in project jOOQ by jOOQ.

the class JavaGenerator method printClassAnnotations.

protected void printClassAnnotations(JavaWriter out, Definition definition, Mode mode) {
    if (generateGeneratedAnnotation()) {
        SchemaDefinition schema = definition.getSchema();
        CatalogDefinition catalog = definition.getCatalog();
        // [#7581] The concrete annotation type depends on the JDK, with
        // javax.annotation.Generated being deprecated in JDK 9
        GeneratedAnnotationType type = generateGeneratedAnnotationType();
        if (type == null)
            type = GeneratedAnnotationType.DETECT_FROM_JDK;
        String generated;
        switch(type) {
            case DETECT_FROM_JDK:
                try {
                    // Seems more reliable than tampering with java.version
                    Reflect.onClass("java.util.Optional").call("of", new Object()).call("stream");
                    generated = "javax.annotation.processing.Generated";
                } catch (ReflectException e) {
                    generated = "javax.annotation.Generated";
                }
                break;
            case JAVAX_ANNOTATION_GENERATED:
                generated = "javax.annotation.Generated";
                break;
            case JAVAX_ANNOTATION_PROCESSING_GENERATED:
                generated = "javax.annotation.processing.Generated";
                break;
            default:
                throw new IllegalStateException("Unsupported type: " + type);
        }
        out.println("@%s(", out.ref(generated));
        if (useSchemaVersionProvider() || useCatalogVersionProvider()) {
            boolean hasCatalogVersion = !StringUtils.isBlank(catalogVersions.get(catalog));
            boolean hasSchemaVersion = !StringUtils.isBlank(schemaVersions.get(schema));
            if (scala)
                out.println("value = %s(", out.ref("scala.Array"));
            else if (kotlin)
                out.println("value = [");
            else
                out.println("value = {");
            out.println("\"https://www.jooq.org\",");
            out.println("\"jOOQ version:%s\"%s", Constants.VERSION, (hasCatalogVersion || hasSchemaVersion ? "," : ""));
            if (hasCatalogVersion)
                out.println("\"catalog version:%s\"%s", escapeString(catalogVersions.get(catalog)), (hasSchemaVersion ? "," : ""));
            if (hasSchemaVersion)
                out.println("\"schema version:%s\"", escapeString(schemaVersions.get(schema)));
            if (scala)
                out.println("),");
            else if (kotlin)
                out.println("],");
            else
                out.println("},");
            if (generateGeneratedAnnotationDate())
                out.println("date = \"" + isoDate + "\",");
            out.println("comments = \"This class is generated by jOOQ\"");
        } else {
            if (scala)
                out.println("value = %s(", out.ref("scala.Array"));
            else if (kotlin)
                out.println("value = [");
            else
                out.println("value = {");
            out.println("\"https://www.jooq.org\",");
            out.println("\"jOOQ version:%s\"", Constants.VERSION);
            if (scala)
                out.println("),");
            else if (kotlin)
                out.println("],");
            else
                out.println("},");
            out.println("comments = \"This class is generated by jOOQ\"");
        }
        out.println(")");
    }
    if (scala) {
    } else if (kotlin)
        out.println("@Suppress(\"UNCHECKED_CAST\")");
    else
        out.println("@%s({ \"all\", \"unchecked\", \"rawtypes\" })", out.ref("java.lang.SuppressWarnings"));
}
Also used : CatalogDefinition(org.jooq.meta.CatalogDefinition) SchemaDefinition(org.jooq.meta.SchemaDefinition) GeneratedAnnotationType(org.jooq.meta.jaxb.GeneratedAnnotationType) ReflectException(org.jooq.tools.reflect.ReflectException)

Example 2 with ReflectException

use of org.jooq.tools.reflect.ReflectException in project jOOQ by jOOQ.

the class MiniJAXB method append.

/**
 * Appends a <code>second</code> JAXB annotated object to a
 * <code>first</code> one using Maven's
 * <code>combine.children="append"</code> semantics.
 *
 * @return The modified <code>first</code> argument.
 */
@SuppressWarnings({ "rawtypes", "unchecked" })
public static <T> T append(T first, T second) {
    if (first == null)
        return second;
    if (second == null)
        return first;
    Class<T> klass = (Class<T>) first.getClass();
    if (klass != second.getClass())
        throw new IllegalArgumentException("Can only append identical types");
    else // [#8527] support enum types
    if (klass.isEnum())
        return first;
    // We're assuming that XJC generated objects are all in the same package
    Package pkg = klass.getPackage();
    try {
        T defaults = klass.getDeclaredConstructor().newInstance();
        for (Method setter : klass.getMethods()) {
            if (setter.getName().startsWith("set")) {
                Method getter;
                try {
                    getter = klass.getMethod("get" + setter.getName().substring(3));
                } catch (NoSuchMethodException e) {
                    getter = klass.getMethod("is" + setter.getName().substring(3));
                }
                Class<?> childType = setter.getParameterTypes()[0];
                Object firstChild = getter.invoke(first);
                Object secondChild = getter.invoke(second);
                Object defaultChild = getter.invoke(defaults);
                if (Collection.class.isAssignableFrom(childType))
                    ((List) firstChild).addAll((List) secondChild);
                else if (secondChild != null && (firstChild == null || firstChild.equals(defaultChild)))
                    setter.invoke(first, secondChild);
                else if (secondChild != null && pkg == childType.getPackage())
                    append(firstChild, secondChild);
                else
                    // All other types cannot be merged
                    ;
            }
        }
    } catch (Exception e) {
        throw new ReflectException(e);
    }
    return first;
}
Also used : Arrays.asList(java.util.Arrays.asList) List(java.util.List) ArrayList(java.util.ArrayList) NodeList(org.w3c.dom.NodeList) XmlList(jakarta.xml.bind.annotation.XmlList) Method(java.lang.reflect.Method) ReflectException(org.jooq.tools.reflect.ReflectException) ConfigurationException(org.jooq.exception.ConfigurationException) SAXException(org.xml.sax.SAXException) IOException(java.io.IOException) ReflectException(org.jooq.tools.reflect.ReflectException) SAXParseException(org.xml.sax.SAXParseException) ParserConfigurationException(javax.xml.parsers.ParserConfigurationException)

Example 3 with ReflectException

use of org.jooq.tools.reflect.ReflectException in project jOOQ by jOOQ.

the class DefaultRecordMapper method init.

private final void init(E instance) {
    Boolean debugVTFL = null;
    Boolean debugVTCP = null;
    Boolean debugMutable = null;
    Boolean debugMutableConstructors = null;
    Boolean debugCPSettings = null;
    Boolean debugRC = null;
    Boolean debugRCSettings = null;
    Boolean debugKClass = null;
    Boolean debugKSettings = null;
    Boolean debugMatchDegreeFlat = null;
    Boolean debugMatchDegreeNested = null;
    // Arrays can be mapped easily
    if (type.isArray()) {
        delegate = new ArrayMapper(instance);
        return;
    }
    if (Stream.class.isAssignableFrom(type)) {
        delegate = r -> (E) Stream.of(((FieldsImpl<R>) rowType).mapper(configuration, Object[].class).map(r));
        return;
    }
    // [#10071] [#11148] Primitive types are abstract! They're mapped by a ConverterProvider only later
    if (Modifier.isAbstract(type.getModifiers()) && !type.isPrimitive()) {
        delegate = new ProxyMapper();
        return;
    }
    // [#2989] [#2836] Records are mapped
    if (AbstractRecord.class.isAssignableFrom(type)) {
        delegate = (RecordMapper<R, E>) new RecordToRecordMapper();
        return;
    }
    // [#10071] Single-field Record1 types can be mapped if there is a ConverterProvider allowing for this mapping
    if ((debugVTFL = fields.length == 1) && (debugVTCP = Tools.converter(configuration, instance, (Class) fields[0].getType(), type) != null)) {
        delegate = new ValueTypeMapper();
        return;
    }
    // [#1340] Allow for using non-public default constructors
    try {
        MutablePOJOMapper m = new MutablePOJOMapper(new ConstructorCall<>(accessible(type.getDeclaredConstructor())), instance);
        // If the no-args constructor is the only one, take it none-theless
        if ((debugMutable = m.isMutable()) || (debugMutableConstructors = type.getDeclaredConstructors().length <= 1)) {
            delegate = m;
            return;
        }
    } catch (NoSuchMethodException ignore) {
        debugMutable = false;
    }
    // [#1336] If no default constructor is present, check if there is a
    // "matching" constructor with the same number of fields as this record
    Constructor<E>[] constructors = (Constructor<E>[]) type.getDeclaredConstructors();
    // [#6868] Prefer public constructors
    Arrays.sort(constructors, (c1, c2) -> (c2.getModifiers() & Modifier.PUBLIC) - (c1.getModifiers() & Modifier.PUBLIC));
    // present use those rather than matching constructors by the number of arguments
    if (debugCPSettings = !FALSE.equals(configuration.settings().isMapConstructorPropertiesParameterNames())) {
        for (Constructor<E> constructor : constructors) {
            ConstructorProperties properties = constructor.getAnnotation(ConstructorProperties.class);
            if (properties != null) {
                delegate = new ImmutablePOJOMapper(constructor, constructor.getParameterTypes(), Arrays.asList(properties.value()), true);
                return;
            }
        }
    }
    // [#7324] Map immutable Kotlin classes by parameter names if kotlin-reflect is on the classpath
    if ((debugKClass = Tools.isKotlinAvailable()) && (debugKSettings = !FALSE.equals(configuration.settings().isMapConstructorParameterNamesInKotlin()))) {
        try {
            Reflect jvmClassMappingKt = Tools.ktJvmClassMapping();
            Reflect kClasses = Tools.ktKClasses();
            Reflect kTypeParameter = Tools.ktKTypeParameter();
            Object klass = jvmClassMappingKt.call("getKotlinClass", type).get();
            Reflect primaryConstructor = kClasses.call("getPrimaryConstructor", klass);
            // It is a Kotlin class
            if (debugKClass = primaryConstructor.get() != null) {
                List<?> parameters = primaryConstructor.call("getParameters").get();
                Class<?> klassType = Tools.ktKClass().type();
                Method getJavaClass = jvmClassMappingKt.type().getMethod("getJavaClass", klassType);
                List<String> parameterNames = new ArrayList<>(parameters.size());
                Class<?>[] parameterTypes = new Class[parameters.size()];
                for (int i = 0; i < parameterTypes.length; i++) {
                    Reflect parameter = Reflect.on(parameters.get(i));
                    Object typeClassifier = parameter.call("getType").call("getClassifier").get();
                    String name = parameter.call("getName").get();
                    // [#8578] If the constructor parameter is a KTypeParameter, we need an additional step to
                    // extract the first upper bounds' classifier, which (hopefully) is a KClass
                    parameterTypes[i] = (Class<?>) getJavaClass.invoke(jvmClassMappingKt.get(), (kTypeParameter.type().isInstance(typeClassifier) ? Reflect.on(typeClassifier).call("getUpperBounds").call("get", 0).call("getClassifier").get() : typeClassifier));
                    // [#8004] Clean up kotlin field name for boolean types
                    String typeName = parameterTypes[i].getName();
                    if (name.startsWith("is") && (boolean.class.getName().equalsIgnoreCase(typeName) || Boolean.class.getName().equals(typeName)))
                        name = getPropertyName(name);
                    parameterNames.add(name);
                }
                Constructor<E> javaConstructor = (Constructor<E>) accessible(this.type.getDeclaredConstructor(parameterTypes));
                delegate = new ImmutablePOJOMapper(javaConstructor, javaConstructor.getParameterTypes(), parameterNames, true);
                return;
            }
        } catch (ReflectException | InvocationTargetException | IllegalAccessException | NoSuchMethodException ignore) {
        }
    }
    boolean mapConstructorParameterNames = TRUE.equals(configuration.settings().isMapConstructorParameterNames());
    // (for a flat POJO)
    for (boolean supportsNesting : new boolean[] { true, false }) {
        for (Constructor<E> constructor : constructors) {
            Class<?>[] parameterTypes = constructor.getParameterTypes();
            // Match the first constructor by parameter length
            if (parameterTypes.length == (supportsNesting ? prefixes().size() : fields.length)) {
                if (supportsNesting)
                    debugMatchDegreeNested = true;
                else
                    debugMatchDegreeFlat = true;
                // [#4627] use parameter names from byte code if available
                if (mapConstructorParameterNames) {
                    Parameter[] parameters = constructor.getParameters();
                    if (parameters != null && parameters.length > 0)
                        delegate = new ImmutablePOJOMapper(constructor, parameterTypes, collectParameterNames(parameters), supportsNesting);
                }
                if (delegate == null)
                    delegate = new ImmutablePOJOMapper(constructor, parameterTypes, emptyList(), supportsNesting);
                return;
            }
        }
        if (supportsNesting)
            debugMatchDegreeNested = false;
        else
            debugMatchDegreeFlat = false;
    }
    // use the first available constructor (thus the choice is undeterministic)
    if (mapConstructorParameterNames) {
        Constructor<E> constructor = constructors[0];
        Parameter[] parameters = constructor.getParameters();
        if (parameters != null && parameters.length > 0) {
            delegate = new ImmutablePOJOMapper(constructor, constructor.getParameterTypes(), collectParameterNames(parameters), false);
            return;
        }
    }
    throw new MappingException(("" + "No DefaultRecordMapper strategy applies to type $type for row type $rowType. Attempted strategies include (in this order):\n" + "- Is type an array (false)?\n" + "- Is type a Stream (false)?\n" + "- Does row type have only 1 column ($debugVTFL) and did ConverterProvider provide a Converter for type ($debugVTCP)?\n" + "- Is type abstract (false)?\n" + "- Is type a org.jooq.Record (false)?\n" + "- Is type a mutable POJO (a POJO with setters or non-final members: $debugMutable) and has a no-args constructor ($debugMutableConstructors)?\n" + "- Does type have a @ConstructorProperties annotated constructor (false) and is Settings.mapConstructorPropertiesParameterNames enabled ($debugCPSettings)?\n" + "- Is type a java.lang.Record ($debugRC) and is Settings.mapRecordComponentParameterNames enabled ($debugRCSettings)?\n" + "- Is type a kotlin class ($debugKClass) and is Settings.mapConstructorParameterNamesInKotlin enabled ($debugKSettings)?\n" + "- Is there a constructor that matches row type's degrees with nested fields ($debugMatchDegreeNested) or flat fields ($debugMatchDegreeFlat)\n" + "- Is Settings.mapConstructorParameterNames enabled ($debugMatchNames)\n" + "").replace("$type", type.toString()).replace("$rowType", rowType.toString()).replace("$debugVTFL", debug(debugVTFL)).replace("$debugVTCP", debug(debugVTCP)).replace("$debugCPSettings", debug(debugCPSettings)).replace("$debugMutableConstructors", debug(debugMutableConstructors)).replace("$debugMutable", debug(debugMutable)).replace("$debugRCSettings", debug(debugRCSettings)).replace("$debugRC", debug(debugRC)).replace("$debugKClass", debug(debugKClass)).replace("$debugKSettings", debug(debugKSettings)).replace("$debugMatchDegreeNested", debug(debugMatchDegreeNested)).replace("$debugMatchDegreeFlat", debug(debugMatchDegreeFlat)).replace("$debugMatchNames", debug(mapConstructorParameterNames)));
}
Also used : TRUE(java.lang.Boolean.TRUE) FALSE(java.lang.Boolean.FALSE) ArrayList(java.util.ArrayList) ReflectException(org.jooq.tools.reflect.ReflectException) MappingException(org.jooq.exception.MappingException) ConstructorProperties(java.beans.ConstructorProperties) Constructor(java.lang.reflect.Constructor) Method(java.lang.reflect.Method) InvocationTargetException(java.lang.reflect.InvocationTargetException) Reflect(org.jooq.tools.reflect.Reflect) Parameter(java.lang.reflect.Parameter)

Aggregations

ReflectException (org.jooq.tools.reflect.ReflectException)3 Method (java.lang.reflect.Method)2 ArrayList (java.util.ArrayList)2 XmlList (jakarta.xml.bind.annotation.XmlList)1 ConstructorProperties (java.beans.ConstructorProperties)1 IOException (java.io.IOException)1 FALSE (java.lang.Boolean.FALSE)1 TRUE (java.lang.Boolean.TRUE)1 Constructor (java.lang.reflect.Constructor)1 InvocationTargetException (java.lang.reflect.InvocationTargetException)1 Parameter (java.lang.reflect.Parameter)1 Arrays.asList (java.util.Arrays.asList)1 List (java.util.List)1 ParserConfigurationException (javax.xml.parsers.ParserConfigurationException)1 ConfigurationException (org.jooq.exception.ConfigurationException)1 MappingException (org.jooq.exception.MappingException)1 CatalogDefinition (org.jooq.meta.CatalogDefinition)1 SchemaDefinition (org.jooq.meta.SchemaDefinition)1 GeneratedAnnotationType (org.jooq.meta.jaxb.GeneratedAnnotationType)1 Reflect (org.jooq.tools.reflect.Reflect)1