SimpleFlatMapper icon indicating copy to clipboard operation
SimpleFlatMapper copied to clipboard

Map Database Column of Array type to POJO

Open ch4nd4n opened this issue 5 years ago • 7 comments

I am trying to map Postgres array(strings) column to array of strings in POJO - https://www.postgresql.org/docs/9.1/arrays.html to map to POJO

In POJO class

  private String[] mystrings;
  // getters and setters etc.

For column data like (postgres data below)

{"AA2891"}

By default it maps to something like

"mystrings": [ "{AA2891}" ],
...

instead of

"mystrings": [ "AA2891" ],
...

Referring to this Test case example - https://github.com/arnaudroger/SimpleFlatMapper/blob/7552995ae9a34ebef69a8a336b529b3095252058/sfm-map/src/test/java/org/simpleflatmapper/test/map/FieldMapperColumnDefinitionTest.java

To fix this I am doing something like

// static initializer
SelectQueryMapperFactory.newInstance()
            .addColumnProperty(
                k -> k.getName().equals("mystrings"), stringArrayGetterFactoryProperty())
            .newMapper(MyObject.class);

Following does not work

private GetterFactoryProperty stringArrayGetterFactoryProperty() {
    return GetterFactoryProperty.forType(
        String.class,
        new IndexedGetter<Object, String[]>() {
            // It never enters here.
          public String[] get(Object rs, int i) {
            try {
              String[] array = (String[]) ((ResultSet) rs).getArray(i).getArray();
              return array; 
            } catch (SQLException e) {
              e.printStackTrace();
            }
            return null;
          }
        });
  }

Changing above code to forType.(String.class ...

  private GetterFactoryProperty stringArrayGetterFactoryProperty() {
    return GetterFactoryProperty.forType(
        String.class,
        new IndexedGetter<Object, String[]>() {
          public String[] get(Object rs, int i) {
            try {
              String[] array = (String[]) ((ResultSet) rs).getArray(i).getArray();
              logger.debug("array: ", array);
              return array;
            } catch (SQLException e) {
              e.printStackTrace();
            }
            return null;
          }
        });
  }

Leads to following exception

java.lang.ArrayStoreException: [Ljava.lang.String;
	at org.simpleflatmapper.reflect.setter.IndexedObjectArraySetter.set(IndexedObjectArraySetter.java:14)
	at org.simpleflatmapper.reflect.setter.IndexedObjectArraySetter.set(IndexedObjectArraySetter.java:5)
	at org.simpleflatmapper.map.fieldmapper.MapperFieldMapper.mapTo(MapperFieldMapper.java:44)
	at org.simpleflatmapper.map.generated.none.AsmMapperFromResultSetToStrings_Inj1_I4.mapFields(Unknown Source)
	at org.simpleflatmapper.map.generated.none.AsmMapperFromResultSetToStrings_Inj1_I4.mapFields(Unknown Source)
	at org.simpleflatmapper.map.mapper.AbstractMapper.map(AbstractMapper.java:23)
	at org.simpleflatmapper.map.fieldmapper.MapperFieldMapper.mapTo(MapperFieldMapper.java:40)
	at org.simpleflatmapper.map.generated.com.juicymiles.data.v2.entities.AsmMapperFromResultSetToFlightConnectionsInj13_I5.mapFields(Unknown Source)
	at org.simpleflatmapper.map.generated.com.juicymiles.data.v2.entities.AsmMapperFromResultSetToFlightConnectionsInj13_I5.mapFields(Unknown Source)
	at org.simpleflatmapper.map.mapper.AbstractMapper.map(AbstractMapper.java:23)
	at org.simpleflatmapper.map.fieldmapper.MapperFieldMapper.mapTo(MapperFieldMapper.java:40)
	at org.simpleflatmapper.map.generated.java.util.AsmMapperFromResultSetToListInj1_I6.mapFields(Unknown Source)
	at org.simpleflatmapper.map.generated.java.util.AsmMapperFromResultSetToListInj1_I6.mapFields(Unknown Source)
	at org.simpleflatmapper.map.mapper.AbstractMapper.map(AbstractMapper.java:23)
	at org.simpleflatmapper.map.fieldmapper.MapperFieldMapper.mapTo(MapperFieldMapper.java:40)
	at org.simpleflatmapper.map.generated.com.juicymiles.data.v2.entities.AsmMapperFromResultSetToFlightRoutesInj6_I7.mapFields(Unknown Source)
	at org.simpleflatmapper.map.generated.com.juicymiles.data.v2.entities.AsmMapperFromResultSetToFlightRoutesInj6_I7.mapFields(Unknown Source)
	at org.simpleflatmapper.map.mapper.AbstractMapper.map(AbstractMapper.java:23)
	at org.simpleflatmapper.map.fieldmapper.MapperFieldMapper.mapTo(MapperFieldMapper.java:40)
	at org.simpleflatmapper.map.generated.java.util.AsmMapperFromResultSetToListInj1_I8.mapFields(Unknown Source)
	at org.simpleflatmapper.map.generated.java.util.AsmMapperFromResultSetToListInj1_I8.mapFields(Unknown Source)
	at org.simpleflatmapper.map.mapper.AbstractMapper.map(AbstractMapper.java:23)
	at org.simpleflatmapper.map.fieldmapper.MapperFieldMapper.mapTo(MapperFieldMapper.java:40)
	at org.simpleflatmapper.map.generated.com.juicymiles.data.v2.entities.AsmMapperFromResultSetToFlightResponsesInj4_I9.mapFields(Unknown Source)
	at org.simpleflatmapper.map.generated.com.juicymiles.data.v2.entities.AsmMapperFromResultSetToFlightResponsesInj4_I9.mapFields(Unknown Source)
	at org.simpleflatmapper.map.mapper.AbstractMapper.map(AbstractMapper.java:23)
	at org.simpleflatmapper.map.mapper.ContextualSourceFieldMapperImpl.map(ContextualSourceFieldMapperImpl.java:38)
	at org.simpleflatmapper.map.mapper.JoinMapperEnumerable.next(JoinMapperEnumerable.java:37)
	at org.simpleflatmapper.util.EnumerableIterator.fetch(EnumerableIterator.java:26)
	at org.simpleflatmapper.util.EnumerableIterator.next(EnumerableIterator.java:33)
	at org.simpleflatmapper.jooq.SelectQueryMapper$ExceptionTranslatorIterator.next(SelectQueryMapper.java:300)
	at org.simpleflatmapper.util.AutoCloseableIterator.next(AutoCloseableIterator.java:34)

Is there an example that I can refer to?

ch4nd4n avatar Dec 23 '19 09:12 ch4nd4n

Will have a look thanks, i think it work directly on a resultset so might be some type thingy not handle properly with jooq

arnaudroger avatar Dec 23 '19 17:12 arnaudroger

Thanks, while debugging String[] array = (String[]) rs.getArray(i).getArray(); this resolves to correct array value that I need to set to POJO. Please refer to the code snippet above. I think there is some problem with flat mapper when target data type to be set is an array of objects. I am not able to nail it down where exactly its errors out. But seems to me like casting exception.

ch4nd4n avatar Dec 23 '19 17:12 ch4nd4n

so I did a quick test


	@Test
	public void testIssue701StringArray() throws SQLException {
		Connection conn = DbHelper.objectDb();

		Configuration cfg = new DefaultConfiguration()
				.set(conn)
				.set(SQLDialect.HSQLDB);


		DSLContext dsl = DSL.using(cfg);


		SelectSelectStep<Record1<String[]>> select = dsl.select(DSL.val(new String[]{"11", "22"}).as("values"));

		SelectQueryMapper<Issue701Pojo> mapper = SelectQueryMapperFactory.newInstance().newMapper(Issue701Pojo.class);

		List<Issue701Pojo> pojos = mapper.asList(select);

		assertEquals(Arrays.asList(new Issue701Pojo(new String[] {"11", "22"})), pojos);


	}

	public static class Issue701Pojo {
		public final String[] values;

		public Issue701Pojo(String[] values) {
			this.values = values;
		}

		@Override
		public String toString() {
			return "Issue701Pojo{" +
					"values=" + Arrays.toString(values) +
					'}';
		}

		@Override
		public boolean equals(Object o) {
			if (this == o) return true;
			if (o == null || getClass() != o.getClass()) return false;

			Issue701Pojo that = (Issue701Pojo) o;

			// Probably incorrect - comparing Object[] arrays with Arrays.equals
			return Arrays.equals(values, that.values);
		}

		@Override
		public int hashCode() {
			return Arrays.hashCode(values);
		}
	}

and it seems to be working fine. I would prob need more to find out actually what is happening, could you send me the query, the Jooq Model Objects in the query and the Pojos? arnaud.roger at gmail.com

arnaudroger avatar Dec 24 '19 17:12 arnaudroger

looking at the ArrayStoreException error it tries to set it at and index on the array instead of the array as such. it relates to the way the mapping as resolved prop -> column.

arnaudroger avatar Dec 24 '19 17:12 arnaudroger

I am not sure if I understand it. Is there any additional info that you need from me that will help?

ch4nd4n avatar Dec 26 '19 06:12 ch4nd4n

yes I would need the list of field the select has, and the object it's mapping to

On Thu, Dec 26, 2019 at 6:38 AM Chandan Kumar [email protected] wrote:

I am not sure if I understand it. Is there any additional info that you need from me that will help?

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/arnaudroger/SimpleFlatMapper/issues/701?email_source=notifications&email_token=ABPAJLMTWMM6BKGEC2MRJXLQ2RGPLA5CNFSM4J6SBJQKYY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGOEHVBA6A#issuecomment-568987768, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABPAJLP5D7DHUSMOSWJYTWTQ2RGPLANCNFSM4J6SBJQA .

arnaudroger avatar Dec 26 '19 12:12 arnaudroger

I will need sometime to pull out relevant code(I can't post the code as is), I will update you in a couple of days time. Thanks for looking into it.

ch4nd4n avatar Dec 27 '19 07:12 ch4nd4n