diff --git a/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorProperties.java b/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorProperties.java new file mode 100644 index 0000000000..33507db369 --- /dev/null +++ b/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorProperties.java @@ -0,0 +1,82 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq.test._; + +import java.beans.ConstructorProperties; +import java.util.Date; + +/** + * @author Lukas Eder + */ +public class ImmutableAuthorWithConstructorProperties { + + private final int id; + private final String firstName; + private final String lastName; + private final Date dateOfBirth; + + // Check if setAccessible is called correctly + @ConstructorProperties({ "firstName", "lastName", "id", "dateOfBirth" }) + ImmutableAuthorWithConstructorProperties(String firstName, String lastName, int id, Date dateOfBirth) { + + this.id = id; + this.firstName = firstName; + this.lastName = lastName; + this.dateOfBirth = dateOfBirth; + } + + // This should never be called + @SuppressWarnings("unused") + ImmutableAuthorWithConstructorProperties(int ID, String firstName, String lastName) { + throw new RuntimeException(); + } + + public int getId() { + return id; + } + + public String getFirstName() { + return firstName; + } + + public String getLastName() { + return lastName; + } + + public Date getDateOfBirth() { + return dateOfBirth; + } +} diff --git a/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorPropertiesAndJPAAnnotations.java b/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorPropertiesAndJPAAnnotations.java new file mode 100644 index 0000000000..9979226719 --- /dev/null +++ b/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorPropertiesAndJPAAnnotations.java @@ -0,0 +1,89 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq.test._; + +import java.beans.ConstructorProperties; +import java.util.Date; + +import javax.persistence.Column; + +/** + * @author Lukas Eder + */ +public class ImmutableAuthorWithConstructorPropertiesAndJPAAnnotations { + + private final String f1; + private final String f2; + private final int f3; + private final Date f4; + + // Check if setAccessible is called correctly + @ConstructorProperties({ "f1", "f2", "f3", "f4" }) + ImmutableAuthorWithConstructorPropertiesAndJPAAnnotations(String firstName, String lastName, int id, + Date dateOfBirth) { + + this.f1 = firstName; + this.f2 = lastName; + this.f3 = id; + this.f4 = dateOfBirth; + } + + // This should never be called + @SuppressWarnings("unused") + ImmutableAuthorWithConstructorPropertiesAndJPAAnnotations(int ID, String firstName, String lastName) { + throw new RuntimeException(); + } + + @Column(name = "FIRST_NAME") + public String getF1() { + return f1; + } + + @Column(name = "LAST_NAME") + public String getF2() { + return f2; + } + + @Column(name = "ID") + public int getF3() { + return f3; + } + + @Column(name = "DATE_OF_BIRTH") + public Date getF4() { + return f4; + } +} diff --git a/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorPropertiesAndJPAAnnotationsAndPublicFields.java b/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorPropertiesAndJPAAnnotationsAndPublicFields.java new file mode 100644 index 0000000000..cef2bf35bc --- /dev/null +++ b/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorPropertiesAndJPAAnnotationsAndPublicFields.java @@ -0,0 +1,76 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq.test._; + +import java.beans.ConstructorProperties; +import java.util.Date; + +import javax.persistence.Column; + +/** + * @author Lukas Eder + */ +public class ImmutableAuthorWithConstructorPropertiesAndJPAAnnotationsAndPublicFields { + + @Column(name = "FIRST_NAME") + public final String f1; + + @Column(name = "LAST_NAME") + public final String f2; + + @Column(name = "ID") + public final int f3; + + @Column(name = "DATE_OF_BIRTH") + public final Date f4; + + // Check if setAccessible is called correctly + @ConstructorProperties({ "f1", "f2", "f3", "f4" }) + ImmutableAuthorWithConstructorPropertiesAndJPAAnnotationsAndPublicFields(String firstName, String lastName, int id, + Date dateOfBirth) { + + this.f1 = firstName; + this.f2 = lastName; + this.f3 = id; + this.f4 = dateOfBirth; + } + + // This should never be called + @SuppressWarnings("unused") + ImmutableAuthorWithConstructorPropertiesAndJPAAnnotationsAndPublicFields(int ID, String firstName, String lastName) { + throw new RuntimeException(); + } +} diff --git a/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorPropertiesAndPublicFields.java b/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorPropertiesAndPublicFields.java new file mode 100644 index 0000000000..9584be3510 --- /dev/null +++ b/jOOQ-test/src/org/jooq/test/_/ImmutableAuthorWithConstructorPropertiesAndPublicFields.java @@ -0,0 +1,66 @@ +/** + * Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com + * All rights reserved. + * + * This software is licensed to you under the Apache License, Version 2.0 + * (the "License"); You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * . Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * . Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * . Neither the name "jOOQ" nor the names of its contributors may be + * used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ +package org.jooq.test._; + +import java.beans.ConstructorProperties; +import java.util.Date; + +/** + * @author Lukas Eder + */ +public class ImmutableAuthorWithConstructorPropertiesAndPublicFields { + + public final String firstName; + public final String lastName; + public final int id; + public final Date dateOfBirth; + + // Check if setAccessible is called correctly + @ConstructorProperties({ "firstName", "lastName", "id", "dateOfBirth" }) + ImmutableAuthorWithConstructorPropertiesAndPublicFields(String firstName, String lastName, int id, Date dateOfBirth) { + + this.firstName = firstName; + this.lastName = lastName; + this.id = id; + this.dateOfBirth = dateOfBirth; + } + + // This should never be called + @SuppressWarnings("unused") + ImmutableAuthorWithConstructorPropertiesAndPublicFields(int ID, String firstName, String lastName) { + throw new RuntimeException(); + } +} diff --git a/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java b/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java index 0c3dbbf9b1..d401d32289 100644 --- a/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java +++ b/jOOQ-test/src/org/jooq/test/_/testcases/FetchTests.java @@ -91,6 +91,10 @@ import org.jooq.test._.FinalWithoutAnnotations; import org.jooq.test._.IBookWithAnnotations; import org.jooq.test._.IBookWithoutAnnotations; import org.jooq.test._.ImmutableAuthor; +import org.jooq.test._.ImmutableAuthorWithConstructorProperties; +import org.jooq.test._.ImmutableAuthorWithConstructorPropertiesAndJPAAnnotations; +import org.jooq.test._.ImmutableAuthorWithConstructorPropertiesAndJPAAnnotationsAndPublicFields; +import org.jooq.test._.ImmutableAuthorWithConstructorPropertiesAndPublicFields; import org.jooq.test._.StaticWithAnnotations; import org.jooq.test._.StaticWithoutAnnotations; @@ -981,6 +985,59 @@ extends BaseTest +(DATE '2010-01-01', CAST('+2 00:00:00' AS INTERVAL DAY TO SECOND)) OVERLAPS +(DATE '2010-01-02', CAST('+2 00:00:00' AS INTERVAL DAY TO SECOND))]]>

The OVERLAPS predicate in jOOQ

@@ -5494,9 +5495,18 @@ public class MyBook1 { // The various "into()" methods allow for fetching records into your custom POJOs: MyBook1 myBook = create.select().from(BOOK).fetchAny().into(MyBook1.class); List myBooks = create.select().from(BOOK).fetch().into(MyBook1.class); -List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class); +List myBooks = create.select().from(BOOK).fetchInto(MyBook1.class);]]> + +

+ Please refer to the Javadoc for more details. +

-// An "immutable" POJO class +

Using "immutable" POJOs

+

+ If jOOQ does not find any default constructor, columns are mapped to the "best-matching" constructor. This allows for using "immutable" POJOs with jOOQ. An example illustrates this: +

+ + myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetch().into(MyBook2.class); -List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook2.class);]]> +List myBooks = create.select(BOOK.ID, BOOK.TITLE).from(BOOK).fetchInto(MyBook2.class); + +// An "immutable" POJO class with a java.beans.ConstructorProperties annotation +public class MyBook3 { + public final String title; + public final int id; + + @ConstructorProperties({ "title", "id"}) + public MyBook2(String title, int id) { + this.title = title; + this.id = id; + } +} + +// With annotated "immutable" POJO classes, there doesn't need to be an exact match between fields and constructor arguments. +// In the below cases, only BOOK.ID is really set onto the POJO, BOOK.TITLE remains null and BOOK.AUTHOR_ID is ignored +MyBook3 myBook = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchAny().into(MyBook3.class); +List myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetch().into(MyBook3.class); +List myBooks = create.select(BOOK.ID, BOOK.AUTHOR_ID).from(BOOK).fetchInto(MyBook3.class); +]]>

Please refer to the Javadoc for more details. diff --git a/jOOQ/src/main/java/org/jooq/Record.java b/jOOQ/src/main/java/org/jooq/Record.java index 119fa0db33..314e1afb39 100644 --- a/jOOQ/src/main/java/org/jooq/Record.java +++ b/jOOQ/src/main/java/org/jooq/Record.java @@ -36,6 +36,7 @@ package org.jooq; +import java.beans.ConstructorProperties; import java.lang.reflect.Constructor; import java.lang.reflect.Proxy; import java.math.BigDecimal; @@ -965,7 +966,8 @@ public interface Record extends FieldProvider, Store { * that might have occurred * @see Convert#convert(Object, Converter) */ - U getValue(Field field, Converter converter) throws IllegalArgumentException, DataTypeException; + U getValue(Field field, Converter converter) throws IllegalArgumentException, + DataTypeException; /** * Get a converted value from this record, providing a field. @@ -983,8 +985,8 @@ public interface Record extends FieldProvider, Store { * that might have occurred * @see Convert#convert(Object, Converter) */ - U getValue(Field field, Converter converter, U defaultValue) throws IllegalArgumentException, - DataTypeException; + U getValue(Field field, Converter converter, U defaultValue) + throws IllegalArgumentException, DataTypeException; /** * Get a converted value from this Record, providing a field name. @@ -1175,6 +1177,23 @@ public interface Record extends FieldProvider, Store { *
  • Public non-final instance member field MY_field
  • *
  • Public non-final instance member field myField
  • * + *

    If no default constructor is available, but at least one constructor + * annotated with ConstructorProperties is available, that one + * is used

    + *
      + *
    • The standard JavaBeans {@link ConstructorProperties} annotation is + * used to match constructor arguments against POJO members or getters.
    • + *
    • If those POJO members or getters have JPA annotations, those will be + * used according to the aforementioned rules, in order to map + * Record values onto constructor arguments.
    • + *
    • If those POJO members or getters don't have JPA annotations, the + * aforementioned naming conventions will be used, in order to map + * Record values onto constructor arguments.
    • + *
    • When several annotated constructors are found, the first one is + * chosen (as reported by {@link Class#getDeclaredConstructors()}
    • + *
    • When invoking the annotated constructor, values are converted onto + * constructor argument types
    • + *
    *

    If no default constructor is available, but at least one "matching" * constructor is available, that one is used

    *
      @@ -1182,7 +1201,8 @@ public interface Record extends FieldProvider, Store { * this record holds fields *
    • When several "matching" constructors are found, the first one is * chosen (as reported by {@link Class#getDeclaredConstructors()}
    • - *
    • When invoking the "matching" + *
    • When invoking the "matching" constructor, values are converted onto + * constructor argument types
    • * *

      If the supplied type is an interface or an abstract class

      * Abstract types are instanciated using Java reflection {@link Proxy} @@ -1293,12 +1313,11 @@ public interface Record extends FieldProvider, Store { *
        *
      • primitive types are supported.
      • *
      - *

      General notes

      - * The resulting record will have its internal "changed" flags set to true - * for all values. This means that {@link UpdatableRecord#store()} will - * perform an INSERT statement. If you wish to store the record - * using an UPDATE statement, use - * {@link Factory#executeUpdate(UpdatableRecord)} instead. + *

      General notes

      The resulting record will have its internal + * "changed" flags set to true for all values. This means that + * {@link UpdatableRecord#store()} will perform an INSERT + * statement. If you wish to store the record using an UPDATE + * statement, use {@link Factory#executeUpdate(UpdatableRecord)} instead. * * @param source The source object to copy data from * @throws MappingException wrapping any reflection exception that might diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java index 0940209b65..108c623fbe 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java @@ -42,8 +42,11 @@ import static org.jooq.impl.Util.getAnnotatedSetters; import static org.jooq.impl.Util.getMatchingGetter; import static org.jooq.impl.Util.getMatchingMembers; import static org.jooq.impl.Util.getMatchingSetters; +import static org.jooq.impl.Util.getPropertyName; import static org.jooq.impl.Util.hasColumnAnnotations; +import static org.jooq.tools.reflect.Reflect.accessible; +import java.beans.ConstructorProperties; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Method; @@ -54,6 +57,7 @@ import java.sql.Date; import java.sql.Time; import java.sql.Timestamp; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; @@ -715,7 +719,7 @@ abstract class AbstractRecord extends AbstractStore implements Record { // [#1340] Allow for using non-public default constructors else { - result = Reflect.accessible(type.getDeclaredConstructor()).newInstance(); + result = accessible(type.getDeclaredConstructor()).newInstance(); } return intoMutablePOJO(type, result); @@ -734,19 +738,83 @@ abstract class AbstractRecord extends AbstractStore implements Record { */ @SuppressWarnings("unchecked") private final E intoImmutablePOJO(Class type) throws Exception { - for (Constructor constructor : (Constructor[]) type.getDeclaredConstructors()) { + Constructor[] constructors = (Constructor[]) type.getDeclaredConstructors(); + + // [#1837] If any java.beans.ConstructorProperties annotations are + // present use those rather than matching constructors by the number of + // arguments + for (Constructor constructor : constructors) { + ConstructorProperties properties = constructor.getAnnotation(ConstructorProperties.class); + + if (properties != null) { + return intoImmutablePOJO(type, constructor, properties); + } + } + + // Without ConstructorProperties, match constructors by matching + // argument length + for (Constructor constructor : constructors) { Class[] parameterTypes = constructor.getParameterTypes(); // Match the first constructor by parameter length if (parameterTypes.length == getFields().size()) { Object[] converted = Util.convert(parameterTypes, intoArray()); - return Reflect.accessible(constructor).newInstance(converted); + return accessible(constructor).newInstance(converted); } } throw new MappingException("No matching constructor found on type " + type + " for record " + this); } + /** + * Create an immutable POJO given a constructor and its associated JavaBeans + * {@link ConstructorProperties} + */ + private final E intoImmutablePOJO(Class type, Constructor constructor, ConstructorProperties properties) throws Exception { + boolean useAnnotations = hasColumnAnnotations(type); + List propertyNames = Arrays.asList(properties.value()); + + Class[] parameterTypes = constructor.getParameterTypes(); + Object[] parameterValues = new Object[parameterTypes.length]; + + for (Field field : getFields()) { + List members; + Method method; + + // Annotations are available and present + if (useAnnotations) { + members = getAnnotatedMembers(type, field.getName()); + method = getAnnotatedGetter(type, field.getName()); + } + + // No annotations are present + else { + members = getMatchingMembers(type, field.getName()); + method = getMatchingGetter(type, field.getName()); + } + + for (java.lang.reflect.Field member : members) { + int index = propertyNames.indexOf(member.getName()); + + if (index >= 0) { + parameterValues[index] = getValue(field); + } + } + + if (method != null) { + String name = getPropertyName(method.getName()); + int index = propertyNames.indexOf(name); + + if (index >= 0) { + parameterValues[index] = getValue(field); + } + } + } + + Object[] converted = Util.convert(parameterTypes, parameterValues); + return accessible(constructor).newInstance(converted); + } + /** * Convert this record into a "mutable" POJO (non-final fields or setters * available) diff --git a/jOOQ/src/main/java/org/jooq/impl/Util.java b/jOOQ/src/main/java/org/jooq/impl/Util.java index f6cae573b8..8df1bfe7e6 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Util.java +++ b/jOOQ/src/main/java/org/jooq/impl/Util.java @@ -988,6 +988,25 @@ final class Util { return result; } + /** + * Get a property name associated with a getter/setter method name. + */ + static String getPropertyName(String methodName) { + String name = methodName; + + if (name.startsWith("is") && name.length() > 2) { + name = name.substring(2, 3).toLowerCase() + name.substring(3); + } + else if (name.startsWith("get") && name.length() > 3) { + name = name.substring(3, 4).toLowerCase() + name.substring(4); + } + else if (name.startsWith("set") && name.length() > 3) { + name = name.substring(3, 4).toLowerCase() + name.substring(4); + } + + return name; + } + /** * Type-safely copy a value from one record to another */