1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package groovy.lang;
35
36 import java.io.IOException;
37 import java.io.StringWriter;
38 import java.io.Writer;
39 import java.util.ArrayList;
40 import java.util.Arrays;
41 import java.util.List;
42
43 import org.codehaus.groovy.runtime.InvokerHelper;
44
45 /***
46 * Represents a String which contains embedded values such as "hello there
47 * ${user} how are you?" which can be evaluated lazily. Advanced users can
48 * iterate over the text and values to perform special processing, such as for
49 * performing SQL operations, the values can be substituted for ? and the
50 * actual value objects can be bound to a JDBC statement. The lovely name of
51 * this class was suggested by Jules Gosnell and was such a good idea, I
52 * couldn't resist :)
53 *
54 * @author <a href="mailto:james@coredevelopers.net">James Strachan</a>
55 * @version $Revision: 1.12 $
56 */
57 public abstract class GString extends GroovyObjectSupport implements Comparable, CharSequence, Writable {
58
59 private Object[] values;
60
61 public GString(Object values) {
62 this.values = (Object[]) values;
63 }
64
65 public GString(Object[] values) {
66 this.values = values;
67 }
68
69
70 public abstract String[] getStrings();
71
72 /***
73 * Overloaded to implement duck typing for Strings
74 * so that any method that can't be evaluated on this
75 * object will be forwarded to the toString() object instead.
76 */
77 public Object invokeMethod(String name, Object args) {
78 try {
79 return super.invokeMethod(name, args);
80 }
81 catch (MissingMethodException e) {
82
83 return InvokerHelper.invokeMethod(toString(), name, args);
84 }
85 }
86
87 public Object[] getValues() {
88 return values;
89 }
90
91 public GString plus(GString that) {
92 List stringList = new ArrayList();
93 List valueList = new ArrayList();
94
95 stringList.addAll(Arrays.asList(getStrings()));
96 valueList.addAll(Arrays.asList(getValues()));
97
98 if (stringList.size() > valueList.size()) {
99 valueList.add("");
100 }
101
102 stringList.addAll(Arrays.asList(that.getStrings()));
103 valueList.addAll(Arrays.asList(that.getValues()));
104
105 final String[] newStrings = new String[stringList.size()];
106 stringList.toArray(newStrings);
107 Object[] newValues = valueList.toArray();
108
109 return new GString(newValues) {
110 public String[] getStrings() {
111 return newStrings;
112 }
113 };
114 }
115
116 public GString plus(String that) {
117 String[] currentStrings = getStrings();
118 String[] newStrings = null;
119 Object[] newValues = null;
120
121 newStrings = new String[currentStrings.length + 1];
122 newValues = new Object[getValues().length + 1];
123 int lastIndex = currentStrings.length;
124 System.arraycopy(currentStrings, 0, newStrings, 0, lastIndex);
125 System.arraycopy(getValues(), 0, newValues, 0, getValues().length);
126 newStrings[lastIndex] = that;
127 newValues[getValues().length] = "";
128
129 final String[] finalStrings = newStrings;
130 return new GString(newValues) {
131
132 public String[] getStrings() {
133 return finalStrings;
134 }
135 };
136 }
137
138 public int getValueCount() {
139 return values.length;
140 }
141
142 public Object getValue(int idx) {
143 return values[idx];
144 }
145
146 public String toString() {
147 StringWriter buffer = new StringWriter();
148 try {
149 writeTo(buffer);
150 }
151 catch (IOException e) {
152 throw new StringWriterIOException(e);
153 }
154 return buffer.toString();
155 }
156
157 public Writer writeTo(Writer out) throws IOException {
158 String[] s = getStrings();
159 int numberOfValues = values.length;
160 for (int i = 0, size = s.length; i < size; i++) {
161 out.write(s[i]);
162 if (i < numberOfValues) {
163 InvokerHelper.write(out, values[i]);
164 }
165 }
166 return out;
167 }
168
169 public boolean equals(Object that) {
170 if (that instanceof GString) {
171 return equals((GString) that);
172 }
173 return false;
174 }
175
176 public boolean equals(GString that) {
177 return toString().equals(that.toString());
178 }
179
180 public int hashCode() {
181 return 37 + toString().hashCode();
182 }
183
184 public int compareTo(Object that) {
185 return toString().compareTo(that.toString());
186 }
187
188 public char charAt(int index) {
189 return toString().charAt(index);
190 }
191
192 public int length() {
193 return toString().length();
194 }
195
196 public CharSequence subSequence(int start, int end) {
197 return toString().subSequence(start, end);
198 }
199 }