urlParams = getUrlParams(exchange.getRequestURI());
179 | Object result = function.apply(urlParams);
180 | responseMsg = result != null ? JsonUtil.toJson(result) : "{}";
181 | } catch (Throwable e) {
182 | responseCode = 500;
183 | responseMsg = JsonUtil.toJson(Maps.to("message", e.getMessage()));
184 | logger.log(Level.SEVERE, "服务异常:" + exchange.getRequestURI(), e);
185 | }
186 | writeResponse(responseCode, responseMsg, exchange);
187 | }
188 |
189 | // 处理静态资源
190 | private void doStaticHandle(HttpExchange exchange) throws IOException {
191 | String path = exchange.getRequestURI().getPath();
192 | String resourcePath = path.substring(context.length());
193 | //jCat/
194 | if (resourcePath.equals("/") || resourcePath.equals("")) {
195 | resourcePath = "/index.html";
196 | }
197 | InputStream stream = getClass().getResourceAsStream("/web" + resourcePath);
198 | if(stream==null){
199 | writeResponse(404,"找不到资源",exchange);
200 | return;
201 | }
202 | exchange.getResponseBody();
203 | byte[] bytes = IOUtils.readFully(stream, -1, false);
204 | exchange.sendResponseHeaders(200, bytes.length);
205 | exchange.getResponseBody().write(bytes);
206 | stream.close();
207 | exchange.getResponseBody().close();
208 | }
209 |
210 | public int copyIo(InputStream in, OutputStream out) throws IOException {
211 | byte[] buffer = new byte[1024];
212 | int len;
213 | int size = 0;
214 | while ((len = in.read(buffer)) != -1) {
215 | size += len;
216 | out.write(buffer, 0, len);
217 | }
218 | return size;
219 | }
220 |
221 | private void writeResponse(int responseCode, String content, HttpExchange exchange) throws IOException {
222 | exchange.getResponseHeaders().set("Content-Type", "application/json; charset=utf-8");
223 | exchange.getResponseHeaders().set("Access-Control-Allow-Origin", "*");
224 | exchange.getResponseHeaders().set("Access-Control-Allow-Headers", "Content-Type, Authorization");
225 | byte[] bytes = content.getBytes(StandardCharsets.UTF_8);
226 | exchange.sendResponseHeaders(responseCode, bytes.length);
227 | // 发送响应内容
228 | OutputStream outputStream = exchange.getResponseBody();
229 | outputStream.write(bytes);
230 | outputStream.close();
231 | }
232 | }
233 |
234 | // String toJson(Object obj) {
235 | // WriteOptions options = new WriteOptionsBuilder().showTypeInfoNever().prettyPrint(true).build();
236 | // return JsonIo.toJson(obj, options);
237 | // }
238 | }
239 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [yyyy] [name of copyright owner]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/jCat-agent/src/main/java/org/coderead/jcat/common/UnsafeUtil.java:
--------------------------------------------------------------------------------
1 | package org.coderead.jcat.common;
2 |
3 | import sun.misc.Unsafe;
4 |
5 | import java.lang.reflect.Field;
6 | import java.util.Arrays;
7 | import java.util.List;
8 | import java.util.Map;
9 |
10 | /**
11 | * @Discription: 强制读取和操作对象属性工具类
12 | * @Author Zaki Chen
13 | * @date 2019/9/30 14:15
14 | **/
15 | public class UnsafeUtil {
16 | public final static Unsafe unsafe;
17 |
18 | static {
19 | try {
20 | Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe");
21 | theUnsafeField.setAccessible(true);
22 | unsafe = (Unsafe) theUnsafeField.get(null);
23 | } catch (NoSuchFieldException | IllegalAccessException e) {
24 | throw new RuntimeException("无法获取unsafe对象", e);
25 | }
26 | }
27 |
28 | /**
29 | * @param field
30 | * @return
31 | */
32 | public static long toAddress(Field field) {
33 | long offset = unsafe.objectFieldOffset(field);
34 | Type type = getType(field);
35 | return offset * 10 + type.valueIndex();
36 | }
37 |
38 | public static Object getValue(Object object, Field field) throws NoSuchFieldException {
39 | long offset = unsafe.objectFieldOffset(field);
40 | Type type = getType(field);
41 | return getValue(object, offset, type);
42 | }
43 |
44 | /**
45 | * 取对象数据
46 | *
47 | * @param object 对象:可以是一个实例对象,也可以是一个类对象
48 | * @param offset 内存偏移地址,如果是数组就是其对应坐标
49 | * @param type 返回数据的类型
50 | * @return
51 | */
52 | public static Object getValue(Object object, long offset, Type type) {
53 | if (object.getClass().getComponentType() != null) {// 数组对象
54 | return getArrayValue(object, (int) offset);
55 | } else if (object instanceof List) {
56 | return ((List>) object).get((int) offset);
57 | } else if (object instanceof Map) {
58 | return ((Map, ?>) object).entrySet().stream().filter(s -> System.identityHashCode(s.getKey()) == offset).findFirst().orElseThrow(() -> new IllegalArgumentException("找不到entry" + offset));
59 | } else if (object instanceof Map.Entry) {
60 | Map.Entry, ?> entry = (Map.Entry, ?>) object;
61 | return offset == 0 ? entry.getKey() : entry.getValue();
62 | }
63 | switch (type) {
64 | case Char:
65 | return unsafe.getChar(object, offset);
66 | case Byte:
67 | return unsafe.getByte(object, offset);
68 | case Short:
69 | return unsafe.getShort(object, offset);
70 | case Integer:
71 | return unsafe.getInt(object, offset);
72 | case Double:
73 | return unsafe.getDouble(object, offset);
74 | case Float:
75 | return unsafe.getFloat(object, offset);
76 | case Long:
77 | return unsafe.getLong(object, offset);
78 | case Boolean:
79 | return unsafe.getBoolean(object, offset);
80 | default:
81 | return unsafe.getObject(object, offset);
82 | }
83 | }
84 |
85 | public static Object[] toArray(Object object) {
86 | Assert.notNull(object, "object不能为空");
87 | Assert.notNull(object.getClass().getComponentType(), "object必须为数组类型");
88 | if (object instanceof int[]) {
89 | return Arrays.stream((int[]) object).boxed().toArray(Integer[]::new);
90 | } else if (object instanceof short[]) {
91 | short[] shortArray = (short[]) object;
92 | Short[] wrapperArray = new Short[shortArray.length];
93 | for (int i = 0; i < shortArray.length; i++) {
94 | wrapperArray[i] = shortArray[i];
95 | }
96 | return wrapperArray;
97 | } else if (object instanceof boolean[]) {
98 | boolean[] boolArray = (boolean[]) object;
99 | Boolean[] wrapperArray = new Boolean[boolArray.length];
100 | for (int i = 0; i < boolArray.length; i++) {
101 | wrapperArray[i] = boolArray[i];
102 | }
103 | return wrapperArray;
104 | } else if (object instanceof double[]) {
105 | return Arrays.stream((double[]) object).boxed().toArray(Double[]::new);
106 | } else if (object instanceof long[]) {
107 | return Arrays.stream((long[]) object).boxed().toArray(Long[]::new);
108 | } else if (object instanceof char[]) {
109 | char[] charArray = (char[]) object;
110 | Character[] wrapperArray = new Character[charArray.length];
111 | for (int i = 0; i < charArray.length; i++) {
112 | wrapperArray[i] = charArray[i];
113 | }
114 | return wrapperArray;
115 | } else if (object instanceof float[]) {
116 | float[] floatArray = (float[]) object;
117 | Float[] wrapperArray = new Float[floatArray.length];
118 | for (int i = 0; i < floatArray.length; i++) {
119 | wrapperArray[i] = floatArray[i];
120 | }
121 | return wrapperArray;
122 | } else if (object instanceof byte[]) {
123 | byte[] byteArray = (byte[]) object;
124 | Byte[] wrapperArray = new Byte[byteArray.length];
125 | for (int i = 0; i < byteArray.length; i++) {
126 | wrapperArray[i] = byteArray[i];
127 | }
128 | return wrapperArray;
129 | }
130 | return (Object[]) object;
131 | }
132 |
133 |
134 | public static void main(String[] args) {
135 | Object[] array = Arrays.stream(new int[]{1, 2, 3}).boxed().toArray();
136 | System.out.println(array);
137 | }
138 |
139 | public static Object getArrayValue(Object object, int index) {
140 | if (object instanceof byte[]) {
141 | return ((byte[]) object)[index];
142 | } else if (object instanceof int[]) {
143 | return ((int[]) object)[index];
144 | } else if (object instanceof short[]) {
145 | return ((short[]) object)[index];
146 | } else if (object instanceof float[]) {
147 | return ((float[]) object)[index];
148 | } else if (object instanceof boolean[]) {
149 | return ((boolean[]) object)[index];
150 | } else if (object instanceof double[]) {
151 | return ((double[]) object)[index];
152 | } else if (object instanceof long[]) {
153 | return ((long[]) object)[index];
154 | } else if (object instanceof char[]) {
155 | return ((char[]) object)[index];
156 | } else if (object instanceof Object[]) {
157 | return ((Object[]) object)[index];
158 | } else {
159 | throw new IllegalArgumentException("对象并非数组");
160 | }
161 | }
162 |
163 | public static int getArrayLength(Object object) {
164 | if (object instanceof byte[]) {
165 | return ((byte[]) object).length;
166 | } else if (object instanceof int[]) {
167 | return ((int[]) object).length;
168 | } else if (object instanceof short[]) {
169 | return ((short[]) object).length;
170 | } else if (object instanceof float[]) {
171 | return ((float[]) object).length;
172 | } else if (object instanceof boolean[]) {
173 | return ((boolean[]) object).length;
174 | } else if (object instanceof double[]) {
175 | return ((double[]) object).length;
176 | } else if (object instanceof long[]) {
177 | return ((long[]) object).length;
178 | } else if (object instanceof char[]) {
179 | return ((char[]) object).length;
180 | } else if (object instanceof Object[]) {
181 | return ((Object[]) object).length;
182 | } else {
183 | throw new IllegalArgumentException("对象并非数组");
184 | }
185 | }
186 |
187 |
188 | /**
189 | * 深度访问子孙节点信息
190 | *
191 | * @param root 根节点对象
192 | * @param address [offset1,type1,offset2,type2,] 其中数组offset就是其访问下标
193 | * @return
194 | */
195 | public static Object getChildValue(Object root, long[] address) {
196 | Object parent = root;
197 | for (int i = 0; i < address.length; i++) {
198 | Type type = Type.indexOf((int) Math.abs(address[i] % 10));
199 | parent = getValue(parent, address[i] / 10, type);
200 | }
201 | return parent;
202 | }
203 |
204 |
205 | /**
206 | * 获取对象的类变量属性值
207 | *
208 | * @param clazz Class对象
209 | * @param propertyName 对象类声明的属性名
210 | * @return
211 | * @throws NoSuchFieldException
212 | */
213 | public static Object getStaticValue(Class clazz, String propertyName) throws NoSuchFieldException {
214 | Field field = clazz.getDeclaredField(propertyName);
215 | long offset = unsafe.staticFieldOffset(field);
216 | return getValue(clazz, offset, getType(field));
217 | }
218 |
219 | /**
220 | * 更新对象实例属性的值
221 | *
222 | * @param object 实例对象
223 | * @param propertyName 实例属性名 非static关键字声明的属性
224 | * @param val 要修改的值
225 | * @return
226 | */
227 | public static void setValue(Object object, String propertyName, Object val) throws NoSuchFieldException {
228 | Field propNameField = object.getClass().getDeclaredField(propertyName);
229 | long offset = unsafe.objectFieldOffset(propNameField);
230 | Type dataType = getType(propNameField);
231 | setValue(object, offset, val, dataType);
232 |
233 | }
234 |
235 | /**
236 | * 修改类属性变量的值
237 | *
238 | * @param clazz 类
239 | * @param propertyName 类属性 static关键字声明的属性
240 | * @param val 值
241 | * @throws NoSuchFieldException
242 | */
243 | public static void setStaticValue(Class clazz, String propertyName, Object val) throws NoSuchFieldException {
244 | Field propNameField = clazz.getDeclaredField(propertyName);
245 | long offset = unsafe.staticFieldOffset(propNameField);
246 | Type dataType = getType(propNameField);
247 | setValue(clazz, offset, val, dataType);
248 | }
249 |
250 |
251 | /**
252 | * 数据值类型枚举
253 | */
254 | public enum Type {
255 | Object,
256 | Byte,
257 | Char,
258 | Boolean,
259 | Short,
260 | Integer,
261 | Double,
262 | Float,
263 | Long; // Collection
264 |
265 | public static Type indexOf(int index) {
266 | return Type.values()[index];
267 | }
268 |
269 | public int valueIndex() {
270 | Type[] values = Type.values();
271 | for (int i = 0; i < values.length; i++) {
272 | if (values[i] == this) {
273 | return i;
274 | }
275 | }
276 | throw new IllegalArgumentException();
277 | }
278 | }
279 |
280 | public static Type getType(Field field) {
281 | Class> type = field.getType();
282 |
283 | if (type.equals(Character.TYPE)) {
284 | return Type.Char;
285 | } else if (type.equals(Byte.TYPE)) {
286 | return Type.Byte;
287 | } else if (type.equals(Short.TYPE)) {
288 | return Type.Short;
289 | } else if (type.equals(Integer.TYPE)) {
290 | return Type.Integer;
291 | } else if (type.equals(Double.TYPE)) {
292 | return Type.Double;
293 | } else if (type.equals(Float.TYPE)) {
294 | return Type.Float;
295 | } else if (type.equals(Long.TYPE)) {
296 | return Type.Long;
297 | } else if (type.equals(Boolean.TYPE)) {
298 | return Type.Boolean;
299 | }/* else if (type.getComponentType() != null) { // 数组类
300 | return Type.Array;
301 | }*/ else {
302 | return Type.Object;
303 | }
304 | }
305 |
306 |
307 | /**
308 | * 放对象数据
309 | *
310 | * @param object 对象:可以是一个实例对象,也可以是一个类对象
311 | * @param offset 内存偏移地址
312 | * @param val 修改后的值
313 | * @param type 被修改属性的声明类型
314 | */
315 | private static void setValue(Object object, long offset, Object val, Type type) {
316 | switch (type) {
317 | case Char:
318 | unsafe.putCharVolatile(object, offset, (Character) val);
319 | break;
320 | case Byte:
321 | unsafe.putByteVolatile(object, offset, (Byte) val);
322 | break;
323 | case Integer:
324 | unsafe.putIntVolatile(object, offset, (Integer) val);
325 | break;
326 | case Double:
327 | unsafe.putDoubleVolatile(object, offset, (Double) val);
328 | break;
329 | case Float:
330 | unsafe.putFloatVolatile(object, offset, (Float) val);
331 | break;
332 | case Long:
333 | unsafe.putLongVolatile(object, offset, (Long) val);
334 | break;
335 | case Boolean:
336 | unsafe.putBooleanVolatile(object, offset, (Boolean) val);
337 | break;
338 | default:
339 | unsafe.putObjectVolatile(object, offset, val);
340 | }
341 | }
342 |
343 | }
--------------------------------------------------------------------------------
/jCat-agent/src/main/java/org/coderead/jcat/common/Assert.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2002-2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 | * use this file except in compliance with the License. You may obtain a copy of
6 | * 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, WITHOUT
12 | * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 | * License for the specific language governing permissions and limitations under
14 | * the License.
15 | */
16 |
17 | package org.coderead.jcat.common;
18 |
19 | /**
20 | * Assertion utility class that assists in validating arguments.
21 | * Useful for identifying programmer errors early and clearly at runtime.
22 | *
23 | *
For example, if the contract of a public method states it does not
24 | * allow {@code null} arguments, Assert can be used to validate that
25 | * contract. Doing this clearly indicates a contract violation when it
26 | * occurs and protects the class's invariants.
27 | *
28 | *
Typically used to validate method arguments rather than configuration
29 | * properties, to check for cases that are usually programmer errors rather than
30 | * configuration errors. In contrast to LOCAL_CONFIG initialization code, there is
31 | * usally no point in falling back to defaults in such methods.
32 | *
33 | *
This class is similar to JUnit's assertion library. If an argument value is
34 | * deemed invalid, an {@link IllegalArgumentException} is thrown (typically).
35 | * For example:
36 | *
37 | *
38 | * Assert.notNull(clazz, "The class must not be null");
39 | * Assert.isTrue(i > 0, "The value must be greater than zero");
40 | *
41 | * Mainly for internal use within the framework; consider Jakarta's Commons Lang
42 | * >= 2.0 for a more comprehensive suite of assertion utilities.
43 | *
44 | * @author Keith Donald
45 | * @author Juergen Hoeller
46 | * @author Colin Sampaleanu
47 | * @author Rob Harrop
48 | * @since 1.1.2
49 | */
50 | public abstract class Assert {
51 |
52 | /**
53 | * Assert a boolean expression, throwing {@code IllegalArgumentException}
54 | * if the test result is {@code false}.
55 | *
Assert.isTrue(i > 0, "The value must be greater than zero");
56 | *
57 | * @param expression a boolean expression
58 | * @param message the exception message to use if the assertion fails
59 | * @throws IllegalArgumentException if expression is {@code false}
60 | */
61 | public static void isTrue(boolean expression, String message) {
62 | if (!expression) {
63 | throw new IllegalArgumentException(message);
64 | }
65 | }
66 |
67 | /**
68 | * Assert a boolean expression, throwing {@code IllegalArgumentException}
69 | * if the test result is {@code false}.
70 | * Assert.isTrue(i > 0);
71 | *
72 | * @param expression a boolean expression
73 | * @throws IllegalArgumentException if expression is {@code false}
74 | */
75 | public static void isTrue(boolean expression) {
76 | isTrue(expression, "[Assertion failed] - this expression must be true");
77 | }
78 |
79 | /**
80 | * Assert that an object is {@code null} .
81 | * Assert.isNull(value, "The value must be null");
82 | *
83 | * @param object the object to check
84 | * @param message the exception message to use if the assertion fails
85 | * @throws IllegalArgumentException if the object is not {@code null}
86 | */
87 | public static void isNull(Object object, String message) {
88 | if (object != null) {
89 | throw new IllegalArgumentException(message);
90 | }
91 | }
92 |
93 | /**
94 | * Assert that an object is {@code null} .
95 | * Assert.isNull(value);
96 | *
97 | * @param object the object to check
98 | * @throws IllegalArgumentException if the object is not {@code null}
99 | */
100 | public static void isNull(Object object) {
101 | isNull(object, "[Assertion failed] - the object argument must be null");
102 | }
103 |
104 | /**
105 | * Assert that an object is not {@code null} .
106 | * Assert.notNull(clazz, "The class must not be null");
107 | *
108 | * @param object the object to check
109 | * @param message the exception message to use if the assertion fails
110 | * @throws IllegalArgumentException if the object is {@code null}
111 | */
112 | public static void notNull(Object object, String message) {
113 | if (object == null) {
114 | throw new IllegalArgumentException(message);
115 | }
116 | }
117 |
118 | /**
119 | * Assert that an object is not {@code null} .
120 | * Assert.notNull(clazz);
121 | *
122 | * @param object the object to check
123 | * @throws IllegalArgumentException if the object is {@code null}
124 | */
125 | public static void notNull(Object object) {
126 | notNull(object, "[Assertion failed] - this argument is required; it must not be null");
127 | }
128 |
129 | /**
130 | * Assert that the given String is not empty; that is,
131 | * it must not be {@code null} and not the empty String.
132 | * Assert.hasLength(name, "Name must not be empty");
133 | *
134 | * @param text the String to check
135 | * @param message the exception message to use if the assertion fails
136 | * @see StringUtils#hasLength
137 | */
138 | public static void hasLength(String text, String message) {
139 | if (!StringUtils.hasLength(text)) {
140 | throw new IllegalArgumentException(message);
141 | }
142 | }
143 |
144 | /**
145 | * Assert that the given String is not empty; that is,
146 | * it must not be {@code null} and not the empty String.
147 | * Assert.hasLength(name);
148 | *
149 | * @param text the String to check
150 | * @see StringUtils#hasLength
151 | */
152 | public static void hasLength(String text) {
153 | hasLength(text,
154 | "[Assertion failed] - this String argument must have length; it must not be null or empty");
155 | }
156 |
157 | /**
158 | * Assert that the given String has valid text content; that is, it must not
159 | * be {@code null} and must contain at least one non-whitespace character.
160 | * Assert.hasText(name, "'name' must not be empty");
161 | *
162 | * @param text the String to check
163 | * @param message the exception message to use if the assertion fails
164 | * @see StringUtils#hasText
165 | */
166 | public static void hasText(String text, String message) {
167 | if (!StringUtils.hasText(text)) {
168 | throw new IllegalArgumentException(message);
169 | }
170 | }
171 |
172 | /**
173 | * Assert that the given String has valid text content; that is, it must not
174 | * be {@code null} and must contain at least one non-whitespace character.
175 | * Assert.hasText(name, "'name' must not be empty");
176 | *
177 | * @param text the String to check
178 | * @see StringUtils#hasText
179 | */
180 | public static void hasText(String text) {
181 | hasText(text,
182 | "[Assertion failed] - this String argument must have text; it must not be null, empty, or blank");
183 | }
184 |
185 | /**
186 | * Assert that the given text does not contain the given substring.
187 | * Assert.doesNotContain(name, "rod", "Name must not contain 'rod'");
188 | *
189 | * @param textToSearch the text to search
190 | * @param substring the substring to find within the text
191 | * @param message the exception message to use if the assertion fails
192 | */
193 | public static void doesNotContain(String textToSearch, String substring, String message) {
194 | if (StringUtils.hasLength(textToSearch) && StringUtils.hasLength(substring) &&
195 | textToSearch.contains(substring)) {
196 | throw new IllegalArgumentException(message);
197 | }
198 | }
199 |
200 | /**
201 | * Assert that the given text does not contain the given substring.
202 | * Assert.doesNotContain(name, "rod");
203 | *
204 | * @param textToSearch the text to search
205 | * @param substring the substring to find within the text
206 | */
207 | public static void doesNotContain(String textToSearch, String substring) {
208 | doesNotContain(textToSearch, substring,
209 | "[Assertion failed] - this String argument must not contain the substring [" + substring + "]");
210 | }
211 |
212 |
213 | /**
214 | * Assert that an array has no null elements.
215 | * Note: Does not complain if the array is empty!
216 | * Assert.noNullElements(array, "The array must have non-null elements");
217 | *
218 | * @param array the array to check
219 | * @param message the exception message to use if the assertion fails
220 | * @throws IllegalArgumentException if the object array contains a {@code null} element
221 | */
222 | public static void noNullElements(Object[] array, String message) {
223 | if (array != null) {
224 | for (Object element : array) {
225 | if (element == null) {
226 | throw new IllegalArgumentException(message);
227 | }
228 | }
229 | }
230 | }
231 |
232 | /**
233 | * Assert that an array has no null elements.
234 | * Note: Does not complain if the array is empty!
235 | * Assert.noNullElements(array);
236 | *
237 | * @param array the array to check
238 | * @throws IllegalArgumentException if the object array contains a {@code null} element
239 | */
240 | public static void noNullElements(Object[] array) {
241 | noNullElements(array, "[Assertion failed] - this array must not contain any null elements");
242 | }
243 |
244 |
245 | /**
246 | * Assert that the provided object is an instance of the provided class.
247 | * Assert.instanceOf(Foo.class, foo);
248 | *
249 | * @param clazz the required class
250 | * @param obj the object to check
251 | * @throws IllegalArgumentException if the object is not an instance of clazz
252 | * @see Class#isInstance
253 | */
254 | public static void isInstanceOf(Class> clazz, Object obj) {
255 | isInstanceOf(clazz, obj, "");
256 | }
257 |
258 | /**
259 | * Assert that the provided object is an instance of the provided class.
260 | * Assert.instanceOf(Foo.class, foo);
261 | *
262 | * @param type the type to check against
263 | * @param obj the object to check
264 | * @param message a message which will be prepended to the message produced by
265 | * the function itself, and which may be used to provide context. It should
266 | * normally end in a ": " or ". " so that the function generate message looks
267 | * ok when prepended to it.
268 | * @throws IllegalArgumentException if the object is not an instance of clazz
269 | * @see Class#isInstance
270 | */
271 | public static void isInstanceOf(Class> type, Object obj, String message) {
272 | notNull(type, "Type to check against must not be null");
273 | if (!type.isInstance(obj)) {
274 | throw new IllegalArgumentException(
275 | (StringUtils.hasLength(message) ? message + " " : "") +
276 | "Object of class [" + (obj != null ? obj.getClass().getName() : "null") +
277 | "] must be an instance of " + type);
278 | }
279 | }
280 |
281 | /**
282 | * Assert that {@code superType.isAssignableFrom(subType)} is {@code true}.
283 | * Assert.isAssignable(Number.class, myClass);
284 | *
285 | * @param superType the super type to check
286 | * @param subType the sub type to check
287 | * @throws IllegalArgumentException if the classes are not assignable
288 | */
289 | public static void isAssignable(Class> superType, Class> subType) {
290 | isAssignable(superType, subType, "");
291 | }
292 |
293 | /**
294 | * Assert that {@code superType.isAssignableFrom(subType)} is {@code true}.
295 | * Assert.isAssignable(Number.class, myClass);
296 | *
297 | * @param superType the super type to check against
298 | * @param subType the sub type to check
299 | * @param message a message which will be prepended to the message produced by
300 | * the function itself, and which may be used to provide context. It should
301 | * normally end in a ": " or ". " so that the function generate message looks
302 | * ok when prepended to it.
303 | * @throws IllegalArgumentException if the classes are not assignable
304 | */
305 | public static void isAssignable(Class> superType, Class> subType, String message) {
306 | notNull(superType, "Type to check against must not be null");
307 | if (subType == null || !superType.isAssignableFrom(subType)) {
308 | throw new IllegalArgumentException(message + subType + " is not assignable to " + superType);
309 | }
310 | }
311 |
312 |
313 | /**
314 | * Assert a boolean expression, throwing {@code IllegalStateException}
315 | * if the test result is {@code false}. Call isTrue if you wish to
316 | * throw IllegalArgumentException on an assertion failure.
317 | * Assert.state(id == null, "The id property must not already be initialized");
318 | *
319 | * @param expression a boolean expression
320 | * @param message the exception message to use if the assertion fails
321 | * @throws IllegalStateException if expression is {@code false}
322 | */
323 | public static void state(boolean expression, String message) {
324 | if (!expression) {
325 | throw new IllegalStateException(message);
326 | }
327 | }
328 |
329 | /**
330 | * Assert a boolean expression, throwing {@link IllegalStateException}
331 | * if the test result is {@code false}.
332 | * Call {@link #isTrue(boolean)} if you wish to
333 | * throw {@link IllegalArgumentException} on an assertion failure.
334 | *
Assert.state(id == null);
335 | *
336 | * @param expression a boolean expression
337 | * @throws IllegalStateException if the supplied expression is {@code false}
338 | */
339 | public static void state(boolean expression) {
340 | state(expression, "[Assertion failed] - this state invariant must be true");
341 | }
342 |
343 | }
344 |
--------------------------------------------------------------------------------
/jCat-agent/src/main/java/org/coderead/jcat/groovyLsp/CompletionHandler.java:
--------------------------------------------------------------------------------
1 | package org.coderead.jcat.groovyLsp;
2 | /**
3 | * @Copyright 源码阅读网 http://coderead.cn
4 | */
5 |
6 | import org.coderead.jcat.common.StringUtils;
7 | import groovy.lang.Closure;
8 | import groovy.lang.Script;
9 | import org.codehaus.groovy.ast.ASTNode;
10 | import org.codehaus.groovy.ast.ClassCodeVisitorSupport;
11 | import org.codehaus.groovy.ast.CompileUnit;
12 | import org.codehaus.groovy.ast.expr.*;
13 | import org.codehaus.groovy.control.SourceUnit;
14 | import org.codehaus.groovy.runtime.DefaultGroovyMethods;
15 |
16 | import java.lang.reflect.Field;
17 | import java.lang.reflect.Method;
18 | import java.lang.reflect.Modifier;
19 | import java.util.*;
20 | import java.util.function.Predicate;
21 | import java.util.function.Supplier;
22 | import java.util.stream.Collectors;
23 |
24 | /**
25 | * @author 鲁班大叔
26 | * @date 2024
27 | */
28 | public class CompletionHandler {
29 | private ClassLoader userLoader;// 应用使用的classLoader
30 | private Class> scriptBaseClass;
31 | Supplier[]> allClass;
32 | public static final String[] defaultImports = {
33 | "java.lang",
34 | "java.util",
35 | "java.io",
36 | "java.net", "groovy.lang", "groovy.util",
37 | "java.math.BigInteger",
38 | "java.math.BigDecimal",
39 | };
40 | // 是否为默认导入的类
41 | private static Predicate> isDefaultClass = c -> Arrays.stream(defaultImports).anyMatch(p -> p.equals(c.getPackage().getName()) || p.equals(c.getName()));
42 |
43 | public CompletionHandler(ClassLoader baseClassLoader, Class> scriptBaseClass) {
44 | this.userLoader = baseClassLoader;
45 | this.scriptBaseClass = scriptBaseClass;
46 | }
47 |
48 | public CompletionHandler() {
49 | this(ClassLoader.getSystemClassLoader(), Script.class);
50 | }
51 |
52 |
53 | public void setAllClass(Supplier[]> allClass) {
54 | this.allClass = allClass;
55 | }
56 |
57 | /**
58 | * 基于光标位置获取提示项
59 | *
60 | * @param position 光标位置 line,column
61 | * @return
62 | */
63 | public List completionByCursor(CompileUnit unit, int[] position) {
64 | FindCompletionNodeVisitor findNodeVisitor = new FindCompletionNodeVisitor(position);
65 | ASTNode astNode = unit.getModules().stream().
66 | flatMap(s -> s.getClasses().stream())
67 | .map(c -> {
68 | c.visitContents(findNodeVisitor);
69 | return findNodeVisitor.node;
70 | })
71 | .filter(Objects::nonNull)
72 | .findFirst().orElse(null);
73 |
74 | if (astNode instanceof VariableExpression) {
75 | return variableCompletion((VariableExpression) astNode);
76 | } else if (astNode instanceof ConstructorCallExpression) {
77 | return constructorCallCompletion((ConstructorCallExpression) astNode);
78 | } else if (astNode instanceof ClassExpression) {
79 | return classCompletion((ClassExpression) astNode);
80 | } else if (astNode instanceof ListExpression) {
81 | return typeCompletion(List.class);
82 | } else if (astNode instanceof MapExpression) {
83 | return typeCompletion(Map.class);
84 | }
85 | // 返回空
86 | return new ArrayList<>();
87 | }
88 |
89 | /**
90 | * 基于关键字获取提示:
91 | * 1.关键字及模板关键字
92 | * 2.groovy.lang.Script类中的方法
93 | * 3.当前定义的元素:变量、方法
94 | * 4.类名
95 | *
96 | * 注意: 勿调用class.getSimpleName或isAnonymousClass 将导致NoClassDefFoundError 或 IllegalAccessError
97 | *
98 | * @return
99 | */
100 | public List completionByKeyword(String keyword, int maxSize) {
101 | //1.关键字过滤
102 | List items = Arrays.stream(JAVA_KEYWORD)
103 | .filter(k -> k.startsWith(keyword))
104 | .limit(maxSize)
105 | .map(this::keywordCompletion).collect(Collectors.toList());
106 | if (items.size() >= maxSize) return items;
107 |
108 | //2.脚本方法过滤
109 | List scriptMethodItems = typeCompletion(scriptBaseClass).stream()
110 | .filter(i -> StringUtils.camelSearch(i.filterText, keyword) > 0)
111 | .limit(maxSize - items.size())
112 | .collect(Collectors.toList());
113 | items.addAll(scriptMethodItems);
114 | if (items.size() >= maxSize) return items;
115 | //3.当前元素过滤 TODO
116 | // unit.getModules().stream().flatMap(m->m.getClasses().stream())
117 |
118 | //4.类名过滤
119 |
120 | /*LinkedList loaders=new LinkedList<>(Collections.singletonList(this.userLoader));
121 | while (loaders.getLast().getParent()!=null){// 获取能访问的loader
122 | loaders.add(loaders.getLast().getParent());
123 | }*/
124 | Class>[] allClasses = allClass == null ? new Class[0] : allClass.get();
125 | Map, Float> scores = new HashMap<>();
126 |
127 | List classItems = Arrays.stream(allClasses)
128 | .filter(a -> Modifier.isPublic(a.getModifiers()))
129 | .filter(a -> !(a.isSynthetic() || a.isArray() || a.getPackage() == null))
130 | // .filter(a -> a.getClassLoader() == null || loaders.stream().anyMatch(l -> a.getClassLoader() == l))// 必须为当前loader能访问的类
131 | .filter(a -> {
132 |
133 | float score = StringUtils.camelSearch(getSimpleClassName(a), keyword);
134 | // 如果是默认包,增加20%分值
135 | scores.put(a, score * (isDefaultClass.test(a) ? 1.2f : 1f));
136 | return score > 0;
137 | })
138 | .sorted((c1, c2) -> (int) (scores.get(c2) * 100 - scores.get(c1) * 100))
139 | .limit(maxSize - items.size()) // 优先级排序
140 | .map(this::classCompletion)
141 | .collect(Collectors.toList());
142 | items.addAll(classItems);
143 |
144 | return items;
145 | }
146 |
147 |
148 | //变量提示
149 | private List variableCompletion(VariableExpression variable) {
150 | Class> typeClass = variable.getType().getTypeClass();
151 | return typeCompletion(typeClass);
152 | }
153 |
154 | //构造方法提示
155 | private List constructorCallCompletion(ConstructorCallExpression exp) {
156 | Class> typeClass = exp.getType().getTypeClass();
157 | return typeCompletion(typeClass);
158 | }
159 |
160 | //类提示
161 | private List classCompletion(ClassExpression exp) {
162 | Class> typeClass = exp.getType().getTypeClass();
163 | List completionItems = typeCompletion(typeClass).stream().filter(t -> Modifier.isStatic(t.modifiers)).collect(Collectors.toList());
164 | completionItems.add(0,keywordCompletion("class"));
165 | return completionItems;
166 | }
167 |
168 |
169 | // TODO 暂不实现
170 | private List methodCallCompletion(MethodCallExpression exp) {
171 | // 获取方法返回结果
172 | return null;
173 | }
174 |
175 | // TODO 暂不实现
176 | private List methodCallCompletion(StaticMethodCallExpression exp) {
177 | return null;
178 | }
179 |
180 |
181 | //通过类型转换定义
182 | public List typeCompletion(Class> type) {
183 | List methods = new ArrayList<>(Arrays.asList(type.getMethods()));
184 | methods.addAll(Arrays.asList(type.getDeclaredMethods()));
185 | List items1 = methods.stream()
186 | .filter(m -> Modifier.isPublic(m.getModifiers()))
187 | .distinct()
188 | .map(this::methodCompletion)
189 | .collect(Collectors.toList());
190 | items1.addAll(groovyCompletion(type));// 添加groovy方法
191 | // 显示 过滤 insertText
192 | List fields = new ArrayList<>(Arrays.asList(type.getFields()));
193 | fields.addAll(Arrays.asList(type.getDeclaredFields()));
194 | List items2 = fields.stream().filter(f -> Modifier.isPublic(f.getModifiers())).map(this::filedCompletion).collect(Collectors.toList());
195 | items1.addAll(items2);
196 | return items1.stream().distinct().collect(Collectors.toList());
197 | }
198 |
199 | protected CompletionItem classCompletion(Class> cla) {
200 | CompletionItem item = new CompletionItem();
201 | String simpleName = getSimpleClassName(cla);
202 | item.label = String.format("%s:%s:%s", simpleName, cla.getPackage().getName(), "");
203 | item.filterText = simpleName;
204 | item.insertText = simpleName;
205 |
206 | if (!isDefaultClass.test(cla)) {
207 | item.insertImportText = "import " + cla.getCanonicalName();//TODO: 在内部类下,存在报找不到类的风险
208 | }
209 | item.kind = "class";
210 | // 因引发ArrayStoreException异常暂时关闭
211 | // item.deprecated = cla.getDeclaredAnnotation(Deprecated.class) != null;
212 | item.modifiers = cla.getModifiers();
213 | return item;
214 | }
215 |
216 | private String getSimpleClassName(Class> cla) {
217 | if (cla.isArray()) {
218 | return getSimpleClassName(cla.getComponentType())+"[]";
219 |
220 | }
221 | return new LinkedList<>(Arrays.asList(cla.getName().split("[.|$]"))).getLast();//TODO:当类名中存在 $将导致不准确
222 | }
223 |
224 | private CompletionItem methodCompletion(Method method) {
225 | return methodCompletion(method, false);
226 | }
227 |
228 | /**
229 | * @param method
230 | * @param isGroovy DefaultGroovyMethods中的静态方法 至少包含一个参数
231 | * @return
232 | */
233 | protected CompletionItem methodCompletion(Method method, boolean isGroovy) {
234 | CompletionItem item = new CompletionItem();
235 | LinkedList> paramTypes = new LinkedList<>(Arrays.asList(method.getParameterTypes()));
236 |
237 | if (isGroovy && Modifier.isStatic(method.getModifiers())) {
238 | paramTypes.remove();// 第一个参数为当前调用对象
239 | }
240 | String paramText = paramTypes.stream().map(this::getSimpleClassName).collect(Collectors.joining(","));
241 | String returnText =getSimpleClassName(method.getReturnType());
242 | item.label = String.format("%s:(%s):%s", method.getName(), paramText, returnText);
243 | item.kind = "method";
244 | item.deprecated = method.getDeclaredAnnotation(Deprecated.class) != null;
245 | item.filterText = method.getName();
246 | item.modifiers = method.getModifiers();
247 | item.groovyMethod = isGroovy;
248 | item.tipsText = paramText;
249 |
250 | if (paramTypes.size() == 1 && paramTypes.getLast().equals(Closure.class)) {
251 | item.insertText = String.format("%s {it-> }", method.getName());
252 | } else if (paramTypes.size() > 1 && paramTypes.getLast().equals(Closure.class)) {
253 | item.insertText = String.format("%s() {it-> }", method.getName());
254 | } else {
255 | item.insertText = String.format("%s()", method.getName());
256 | }
257 | return item;
258 | }
259 |
260 | protected CompletionItem filedCompletion(Field field) {
261 | CompletionItem item = new CompletionItem();
262 | item.label = String.format("%s:%s:%s", field.getName(), "", getSimpleClassName(field.getType()));
263 | item.filterText = field.getName();
264 | item.kind = "field";
265 | item.deprecated = field.getDeclaredAnnotation(Deprecated.class) != null;
266 | item.modifiers = field.getModifiers();
267 | item.insertText = field.getName();
268 | return item;
269 | }
270 |
271 | protected List groovyCompletion(Class type) {
272 | return Arrays.stream(DefaultGroovyMethods.class.getDeclaredMethods())
273 | .filter(m -> Modifier.isPublic(m.getModifiers()) && Modifier.isStatic(m.getModifiers()))
274 | .filter(m -> m.getParameters().length > 0)
275 | .filter(m -> m.getParameters()[0].getType().isAssignableFrom(type))
276 | .map(m -> methodCompletion(m, true))
277 | .collect(Collectors.toList());
278 | }
279 |
280 | protected CompletionItem keywordCompletion(String keyword) {
281 | CompletionItem item = new CompletionItem();
282 | item.label = keyword;
283 | item.filterText = keyword;
284 | item.kind = "keyword";
285 | item.insertText = keyword;
286 |
287 | return item;
288 | }
289 |
290 |
291 | //
292 | // 基于光标位置 找到可提示的项目
293 | /*
294 | 基于光标位置 找到可提示的项目,有以下5种节点:
295 | 1.VariableExpression
296 | 2.MethodCallExpression
297 | 3.ConstructorCallExpression
298 | 4.StaticMethodCallExpression
299 | 5.ClassExpression
300 | */
301 | private class FindCompletionNodeVisitor extends ClassCodeVisitorSupport {
302 | private int[] position;
303 | ASTNode node;
304 |
305 | public FindCompletionNodeVisitor(int[] position) {
306 | this.position = position;
307 | }
308 |
309 | protected SourceUnit getSourceUnit() {
310 | return null;
311 | }
312 |
313 | @Override
314 | public void visitVariableExpression(VariableExpression expression) {
315 | super.visitVariableExpression(expression);
316 | visitNode(expression);
317 | }
318 |
319 | @Override
320 | public void visitMethodCallExpression(MethodCallExpression call) {
321 | super.visitMethodCallExpression(call);
322 | visitNode(call);
323 | }
324 |
325 | @Override
326 | public void visitConstructorCallExpression(ConstructorCallExpression call) {
327 | super.visitConstructorCallExpression(call);
328 | visitNode(call);
329 | }
330 |
331 | @Override
332 | public void visitStaticMethodCallExpression(StaticMethodCallExpression call) {
333 | super.visitStaticMethodCallExpression(call);
334 | visitNode(call);
335 | }
336 |
337 | @Override
338 | public void visitClassExpression(ClassExpression expression) {
339 | super.visitClassExpression(expression);
340 | visitNode(expression);
341 | }
342 |
343 | @Override
344 | public void visitListExpression(ListExpression expression) {
345 | super.visitListExpression(expression);
346 | visitNode(expression);
347 | }
348 |
349 | @Override
350 | public void visitMapExpression(MapExpression expression) {
351 | super.visitMapExpression(expression);
352 | visitNode(expression);
353 | }
354 |
355 | void visitNode(ASTNode node) {
356 | if (node.getLastLineNumber() == position[0] && node.getLastColumnNumber() == position[1]) {
357 | this.node = node;
358 | }
359 | }
360 | }
361 |
362 |
363 | private static final String JAVA_KEYWORD[] = {
364 | "abstract", "assert", "boolean", "break", "byte", "case", "catch", "char", "class", "continue", "default", "do", "double", "else", "enum", "extends", "final", "finally", "float", "for", "if", "implements", "import", "int", "interface", "instanceof", "long", "native", "new", "package", "private", "protected", "public", "return", "short", "static", "strictfp", "super", "switch", "synchronized", "this", "throw", "throws", "transient", "try", "void", "volatile", "while"
365 | };
366 | }
367 |
--------------------------------------------------------------------------------
/JCat-web/src/components/Console.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 代码示例
6 |
7 |
15 |
16 | {{ item.title }}
17 |
18 |
19 |
20 |
21 |
22 |
23 | mdi-play执行
25 |
26 | mdi-refresh
28 |
40 |
41 |
51 |
52 | 请选择ClassLoader:
53 |
54 |
55 |
56 | mdi-cog设置
58 |
59 |
60 |
69 |
70 |
75 | {{ shortcut.name
76 | }}{{ shortcut.key }}
77 |
78 |
79 |
80 |
86 |
87 |
92 |
93 | {{history.code.trim()}}
94 |
99 |
mdi-alert-octagon
102 |
{{ history.error.errorStack }}
103 |
{{ history.error.errorType }}:{{
105 | history.error.errorMessage
106 | }}
108 |
详情..
114 |
115 |
116 |
117 |
121 | "{{ history.result.value }}"
122 |
123 | {{ history.result.value }}
124 |
125 |
126 |
127 |
128 |
129 |
136 |
137 | 加载更多..
146 |
147 |
148 | {{ item.name }} =
149 |
150 |
151 |
155 | "{{ item.value }}"
156 |
157 | {{ item.value }}
158 |
159 |
160 | {{
161 | getSimpleClassName(item.type)
162 | }}
163 | [{{ item.childSize }}]
168 | @{{ item.objectId }}
169 |
170 | size={{ item.childSize }}
172 | "{{ item.value }}"
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
198 | 保存新文件
199 |
200 |
207 |
208 |
209 |
210 | 取消
213 | 保存
220 |
221 |
222 |
223 |
224 |
225 |
226 |
539 |
540 |
--------------------------------------------------------------------------------