1 | /* |
2 | * Copyright 2007 brunella ltd |
3 | * |
4 | * Licensed under the LGPL Version 3 (the "License"); |
5 | * you may not use this file except in compliance with the License. |
6 | * |
7 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
8 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
9 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
10 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
11 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
12 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
13 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
14 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
15 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
16 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
17 | * THE POSSIBILITY OF SUCH DAMAGE. |
18 | */ |
19 | package sf.qof.adapter; |
20 | |
21 | import static sf.qof.codegen.Constants.*; |
22 | |
23 | import java.util.HashSet; |
24 | import java.util.Set; |
25 | |
26 | import org.objectweb.asm.Label; |
27 | import org.objectweb.asm.Type; |
28 | |
29 | import net.sf.cglib.core.CodeEmitter; |
30 | import net.sf.cglib.core.Local; |
31 | import net.sf.cglib.core.Signature; |
32 | import sf.qof.QueryObjectFactory; |
33 | import sf.qof.mapping.ParameterMapping; |
34 | import sf.qof.mapping.ResultMapping; |
35 | |
36 | /** |
37 | * EnumerationAdapter is a generator mapping adapter for Java enumerations. |
38 | * |
39 | * <p>It uses <code>enum.name()</code> to map an enumeration to a VARCHAR and |
40 | * <code>enum.valueOf(String)</code> to map it back.</p> |
41 | */ |
42 | public class EnumerationAdapter implements GeneratorMappingAdapter { |
43 | |
44 | public void generateFromResult(ResultMapping resultMapping, CodeEmitter co, Local result, int[] indexes) { |
45 | co.load_local(result); |
46 | co.push(indexes[0]); |
47 | co.invoke_interface(result.getType(), SIG_getString); |
48 | emitProcessResult(resultMapping, co); |
49 | } |
50 | |
51 | public void generateFromResultSet(ResultMapping resultMapping, CodeEmitter co, Local resultSet, String[] columns) { |
52 | co.load_local(resultSet); |
53 | co.push(columns[0]); |
54 | co.invoke_interface(TYPE_ResultSet, SIG_getStringNamed); |
55 | emitProcessResult(resultMapping, co); |
56 | } |
57 | |
58 | private void emitProcessResult(ResultMapping resultMapping, CodeEmitter co) { |
59 | Local localResult = co.make_local(TYPE_String); |
60 | co.store_local(localResult); |
61 | Label labelNull = co.make_label(); |
62 | co.load_local(localResult); |
63 | co.ifnull(labelNull); |
64 | co.load_local(localResult); |
65 | Type enumType; |
66 | if (resultMapping.getConstructor() != null) { |
67 | enumType = Type.getType(resultMapping.getConstructor() |
68 | .getParameterTypes()[resultMapping.getConstructorParameter() - 1]); |
69 | } else if (resultMapping.getMapKeyType() != null) { |
70 | enumType = Type.getType(resultMapping.getMapKeyType()); |
71 | } else { |
72 | enumType = Type.getType(resultMapping.getType()); |
73 | } |
74 | co.invoke_static(enumType, new Signature("valueOf", "(Ljava/lang/String;)" + enumType.getDescriptor())); |
75 | Label labelEnd = co.make_label(); |
76 | co.goTo(labelEnd); |
77 | co.mark(labelNull); |
78 | co.aconst_null(); |
79 | co.mark(labelEnd); |
80 | } |
81 | |
82 | public void generateToPreparedStatement(ParameterMapping parameterMapping, CodeEmitter co, Local preparedStatement, int[] indexes, Local indexOffset) { |
83 | Local localEnum = co.make_local(); |
84 | Label labelNull = co.make_label(); |
85 | Label labelEnd = co.make_label(); |
86 | co.store_local(localEnum); |
87 | co.load_local(localEnum); |
88 | co.ifnull(labelNull); |
89 | // not null |
90 | co.load_local(localEnum); |
91 | co.invoke_virtual(Type.getType(Enum.class), new Signature("name", "()Ljava/lang/String;")); |
92 | Local localString = co.make_local(TYPE_String); |
93 | co.store_local(localString); |
94 | co.load_local(preparedStatement); |
95 | co.push(indexes[0]); |
96 | if (indexOffset != null) { |
97 | co.load_local(indexOffset); |
98 | co.math(CodeEmitter.ADD, TYPE_int); |
99 | } |
100 | co.load_local(localString); |
101 | co.invoke_interface(TYPE_PreparedStatement, SIG_setString); |
102 | co.goTo(labelEnd); |
103 | |
104 | co.mark(labelNull); |
105 | // null |
106 | co.load_local(preparedStatement); |
107 | co.push(indexes[0]); |
108 | if (indexOffset != null) { |
109 | co.load_local(indexOffset); |
110 | co.math(CodeEmitter.ADD, TYPE_int); |
111 | } |
112 | co.push(java.sql.Types.VARCHAR); |
113 | co.invoke_interface(TYPE_PreparedStatement, SIG_setNull); |
114 | |
115 | co.mark(labelEnd); |
116 | } |
117 | |
118 | public void generateRegisterOutputParameters(ResultMapping resultMapping, CodeEmitter co, Local callableStatement, |
119 | int[] indexes) { |
120 | co.load_local(callableStatement); |
121 | co.push(indexes[0]); |
122 | co.push(java.sql.Types.VARCHAR); |
123 | co.invoke_interface(TYPE_CallableStatement, SIG_registerOutParameter); |
124 | } |
125 | |
126 | public int getNumberOfColumns() { |
127 | return 1; |
128 | } |
129 | |
130 | public Set<Class<?>> getTypes() { |
131 | return typeSet; |
132 | } |
133 | |
134 | private static Set<Class<?>> typeSet; |
135 | |
136 | static { |
137 | typeSet = new HashSet<Class<?>>(); |
138 | typeSet.add(Enum.class); |
139 | } |
140 | |
141 | private final static EnumerationAdapter generator = new EnumerationAdapter(); |
142 | |
143 | /** |
144 | * Register the mapping adapter with the default name "enum". |
145 | */ |
146 | public static void register() { |
147 | register("enum"); |
148 | } |
149 | |
150 | /** |
151 | * Register the mapping adapter with the specified name. |
152 | * |
153 | * @param typeName type name |
154 | */ |
155 | public static void register(String typeName) { |
156 | QueryObjectFactory.registerMapper(typeName, generator); |
157 | } |
158 | |
159 | } |