Skip to content

Commit 7355fe3

Browse files
author
Alexandre Dutra
committed
JAVA-565: Codec support for Java arrays.
This commit introduces codecs that map CQL types to Java arrays directly. Object arrays and arrays of primitive types are both supported.
1 parent 71ac29c commit 7355fe3

11 files changed

Lines changed: 940 additions & 233 deletions

File tree

changelog/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
- [new feature] JAVA-846: Provide custom codecs library as an extra module.
1818
- [new feature] JAVA-742: Codec Support for JSON.
1919
- [new feature] JAVA-606: Codec support for Java 8.
20+
- [new feature] JAVA-565: Codec support for Java arrays.
2021

2122
Merged from 2.1 branch:
2223

driver-core/src/test/java/com/datastax/driver/core/TypeCodecArraysIntegrationTest.java

Lines changed: 0 additions & 233 deletions
This file was deleted.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
/*
2+
* Copyright (C) 2012-2015 DataStax Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package com.datastax.driver.extras.codecs.arrays;
17+
18+
import java.lang.reflect.Array;
19+
20+
import static com.google.common.base.Preconditions.checkArgument;
21+
22+
import com.datastax.driver.core.DataType;
23+
import com.datastax.driver.core.ParseUtils;
24+
import com.datastax.driver.core.TypeCodec;
25+
import com.datastax.driver.core.exceptions.InvalidTypeException;
26+
27+
import static com.datastax.driver.core.ParseUtils.skipSpaces;
28+
29+
/**
30+
* Base class for all codecs dealing with Java arrays.
31+
* This class aims to reduce the amount of code required to create such codecs.
32+
*
33+
* @param <T> The Java array type this codec handles
34+
*/
35+
public abstract class AbstractArrayCodec<T> extends TypeCodec<T> {
36+
37+
/**
38+
* @param cqlType The CQL type. Must be a list type.
39+
* @param javaClass The Java type. Must be an array class.
40+
*/
41+
public AbstractArrayCodec(DataType.CollectionType cqlType, Class<T> javaClass) {
42+
super(cqlType, javaClass);
43+
checkArgument(cqlType.getName() == DataType.Name.LIST, "Expecting CQL list type, got %s", cqlType);
44+
checkArgument(javaClass.isArray(), "Expecting Java array class, got %s", javaClass);
45+
}
46+
47+
@Override
48+
public String format(T array) throws InvalidTypeException {
49+
if (array == null)
50+
return "NULL";
51+
int length = Array.getLength(array);
52+
StringBuilder sb = new StringBuilder();
53+
sb.append('[');
54+
for (int i = 0; i < length; i++) {
55+
if (i != 0)
56+
sb.append(",");
57+
formatElement(sb, array, i);
58+
}
59+
sb.append(']');
60+
return sb.toString();
61+
}
62+
63+
@Override
64+
public T parse(String value) throws InvalidTypeException {
65+
if (value == null || value.isEmpty() || value.equalsIgnoreCase("NULL"))
66+
return null;
67+
68+
int idx = skipSpaces(value, 0);
69+
if (value.charAt(idx++) != '[')
70+
throw new InvalidTypeException(String.format("cannot parse list value from \"%s\", at character %d expecting '[' but got '%c'", value, idx, value.charAt(idx)));
71+
72+
idx = skipSpaces(value, idx);
73+
74+
if (value.charAt(idx) == ']')
75+
return newInstance(0);
76+
77+
// first pass: determine array length
78+
int length = getArrayLength(value, idx);
79+
80+
// second pass: parse elements
81+
T array = newInstance(length);
82+
int i = 0;
83+
for( ; idx < value.length(); i++) {
84+
int n = skipLiteral(value, idx);
85+
parseElement(value.substring(idx, n), array, i);
86+
idx = skipSpaces(value, n);
87+
if (value.charAt(idx) == ']')
88+
return array;
89+
idx = skipComma(value, idx);
90+
idx = skipSpaces(value, idx);
91+
}
92+
93+
throw new InvalidTypeException(String.format("Malformed list value \"%s\", missing closing ']'", value));
94+
}
95+
96+
/**
97+
* Create a new array instance with the given size.
98+
*
99+
* @param size The size of the array to instantiate.
100+
* @return a new array instance with the given size.
101+
*/
102+
protected abstract T newInstance(int size);
103+
104+
/**
105+
* Format the {@code index}th element of {@code array} to {@code output}.
106+
*
107+
* @param output The StringBuilder to write to.
108+
* @param array The array to read from.
109+
* @param index The element index.
110+
*/
111+
protected abstract void formatElement(StringBuilder output, T array, int index);
112+
113+
/**
114+
* Parse the {@code index}th element of {@code array} from {@code input}.
115+
*
116+
* @param input The String to read from.
117+
* @param array The array to write to.
118+
* @param index The element index.
119+
*/
120+
protected abstract void parseElement(String input, T array, int index);
121+
122+
private int getArrayLength(String value, int idx) {
123+
int length = 1;
124+
for( ; idx < value.length(); length++) {
125+
idx = skipLiteral(value, idx);
126+
idx = skipSpaces(value, idx);
127+
if (value.charAt(idx) == ']')
128+
break;
129+
idx = skipComma(value, idx);
130+
idx = skipSpaces(value, idx);
131+
}
132+
return length;
133+
}
134+
135+
private int skipComma(String value, int idx) {
136+
if (value.charAt(idx) != ',')
137+
throw new InvalidTypeException(String.format("Cannot parse list value from \"%s\", at character %d expecting ',' but got '%c'", value, idx, value.charAt(idx)));
138+
return idx + 1;
139+
}
140+
141+
private int skipLiteral(String value, int idx) {
142+
try {
143+
return ParseUtils.skipCQLValue(value, idx);
144+
} catch (IllegalArgumentException e) {
145+
throw new InvalidTypeException(String.format("Cannot parse list value from \"%s\", invalid CQL value at character %d", value, idx), e);
146+
}
147+
}
148+
149+
}

0 commit comments

Comments
 (0)