Skip to content

Commit a0bbb52

Browse files
authored
JAVA-1159: Document workaround for using tuple with udt field in Mapper (apache#1166)
1 parent fe61331 commit a0bbb52

3 files changed

Lines changed: 136 additions & 1 deletion

File tree

changelog/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
- [improvement] JAVA-2003: Simplify CBUtil internal API to improve performance.
1414
- [improvement] JAVA-2002: Reimplement TypeCodec.accepts to improve performance.
1515
- [documentation] JAVA-2041: Deprecate cross-DC failover in DCAwareRoundRobinPolicy.
16+
- [documentation] JAVA-1159: Document workaround for using tuple with udt field in Mapper.
1617

1718

1819
### 3.6.0

driver-mapping/src/test/java/com/datastax/driver/mapping/MapperUDTCollectionsTest.java

Lines changed: 112 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,14 @@
1515
*/
1616
package com.datastax.driver.mapping;
1717

18+
import static org.assertj.core.api.Assertions.assertThat;
1819
import static org.testng.Assert.assertEquals;
1920

2021
import com.datastax.driver.core.CCMTestsSupport;
22+
import com.datastax.driver.core.DataType;
23+
import com.datastax.driver.core.TupleType;
24+
import com.datastax.driver.core.TupleValue;
25+
import com.datastax.driver.core.UserType;
2126
import com.datastax.driver.core.utils.CassandraVersion;
2227
import com.datastax.driver.core.utils.MoreObjects;
2328
import com.datastax.driver.mapping.annotations.FrozenKey;
@@ -30,6 +35,7 @@
3035
import java.util.List;
3136
import java.util.Map;
3237
import java.util.Set;
38+
import java.util.UUID;
3339
import org.testng.annotations.Test;
3440
import org.testng.collections.Lists;
3541

@@ -47,7 +53,8 @@ public void onTestContextInitialized() {
4753
+ "s set<frozen<\"Sub\">>, "
4854
+ "m1 map<int,frozen<\"Sub\">>, "
4955
+ "m2 map<frozen<\"Sub\">,int>, "
50-
+ "m3 map<frozen<\"Sub\">,frozen<\"Sub\">>)");
56+
+ "m3 map<frozen<\"Sub\">,frozen<\"Sub\">>)",
57+
"CREATE TABLE user_with_tuple (id uuid PRIMARY KEY, sub tuple<text,\"Sub\">)");
5158
}
5259

5360
@UDT(name = "Sub", caseSensitiveType = true)
@@ -198,4 +205,108 @@ public void testNullCollection() {
198205

199206
assertEquals(m.get(c.getId()), c);
200207
}
208+
209+
@Table(name = "user_with_tuple")
210+
public static class UserWithTuple {
211+
@PartitionKey private UUID id;
212+
213+
private TupleValue sub;
214+
215+
public UUID getId() {
216+
return id;
217+
}
218+
219+
public void setId(UUID id) {
220+
this.id = id;
221+
}
222+
223+
public TupleValue getSub() {
224+
return sub;
225+
}
226+
227+
public void setSub(TupleValue sub) {
228+
this.sub = sub;
229+
}
230+
231+
@Override
232+
public boolean equals(Object o) {
233+
if (this == o) return true;
234+
if (o == null || getClass() != o.getClass()) return false;
235+
236+
UserWithTuple that = (UserWithTuple) o;
237+
238+
if (id != null ? !id.equals(that.id) : that.id != null) return false;
239+
return sub != null ? sub.equals(that.sub) : that.sub == null;
240+
}
241+
242+
@Override
243+
public int hashCode() {
244+
int result = id != null ? id.hashCode() : 0;
245+
result = 31 * result + (sub != null ? sub.hashCode() : 0);
246+
return result;
247+
}
248+
}
249+
250+
@UDT(name = "Sub", caseSensitiveType = true)
251+
// Create a separate class with the same structure to test effectiveness of udtCodec
252+
public static class SubInTuple {
253+
private int i;
254+
255+
public SubInTuple() {}
256+
257+
public SubInTuple(int i) {
258+
this.i = i;
259+
}
260+
261+
public int getI() {
262+
return i;
263+
}
264+
265+
public void setI(int i) {
266+
this.i = i;
267+
}
268+
269+
@Override
270+
public boolean equals(Object other) {
271+
if (other instanceof SubInTuple) {
272+
SubInTuple that = (SubInTuple) other;
273+
return this.i == that.i;
274+
}
275+
return false;
276+
}
277+
278+
@Override
279+
public int hashCode() {
280+
return MoreObjects.hashCode(i);
281+
}
282+
}
283+
284+
/**
285+
* Validates that tables having a tuple that has a UDT field can be handled by the object mapper
286+
* assuming a udt codec has been registered with {@link MappingManager#udtCodec(Class)}
287+
*
288+
* @jira_ticket JAVA-1159
289+
* @test_category object_mapper
290+
*/
291+
@Test(groups = "short")
292+
public void should_be_able_to_create_entity_from_table_having_tuple_with_udt() {
293+
MappingManager manager = new MappingManager(session());
294+
Mapper<UserWithTuple> mapper = manager.mapper(UserWithTuple.class);
295+
296+
// register a codec using udtCodec, this is mandatory.
297+
manager.udtCodec(SubInTuple.class);
298+
299+
UserType subType = cluster().getMetadata().getKeyspace(keyspace).getUserType("\"Sub\"");
300+
TupleType tt = cluster().getMetadata().newTupleType(DataType.text(), subType);
301+
TupleValue tv = tt.newValue("seven", new SubInTuple(7));
302+
303+
UserWithTuple user = new UserWithTuple();
304+
user.setId(UUID.randomUUID());
305+
user.setSub(tv);
306+
307+
mapper.save(user);
308+
309+
UserWithTuple retrieved = mapper.get(user.getId());
310+
assertThat(retrieved).isEqualTo(user);
311+
}
201312
}

manual/object_mapper/creating/README.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -359,9 +359,32 @@ private Map<Address, List<String>> frozenKeyValueMap;
359359
private Map<String, List<Address>> frozenValueMap;
360360
```
361361

362+
With regards to tuples, these can be represented as `TupleValue` fields, i.e.:
363+
364+
```java
365+
@Frozen
366+
private TupleValue myTupleValue;
367+
```
368+
369+
Please note however that tuples are not a good fit for the mapper since it is up to the user to
370+
resolve the associated `TupleType` when creating and accessing `TupleValue`s and properly use the
371+
right types since java type information is not known.
372+
373+
Also note that `@UDT`-annotated classes are not implicitly registered with `TupleValue` like they
374+
otherwise are because the mapper is not able to identify the cql type information at the time
375+
entities are constructed.
376+
377+
To work around this, one may use [udtCodec] to register a `TypeCodec` that the mapper can use
378+
to figure out how to appropriately handle UDT conversion, i.e.:
379+
380+
```java
381+
mappingManager.udtCodec(Address.class);
382+
```
383+
362384
[frozen]:http://docs.datastax.com/en/drivers/java/3.6/com/datastax/driver/mapping/annotations/Frozen.html
363385
[frozenkey]:http://docs.datastax.com/en/drivers/java/3.6/com/datastax/driver/mapping/annotations/FrozenKey.html
364386
[frozenvalue]:http://docs.datastax.com/en/drivers/java/3.6/com/datastax/driver/mapping/annotations/FrozenValue.html
387+
[udtCodec]:https://docs.datastax.com/en/drivers/java/3.6/com/datastax/driver/mapping/MappingManager.html#udtCodec-java.lang.Class-
365388

366389
#### Prefer Frozen Collections
367390

0 commit comments

Comments
 (0)