reproto 0.0.4__tar.gz → 0.0.5__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- reproto-0.0.5/.git/COMMIT_EDITMSG +24 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/config +3 -0
- reproto-0.0.5/.git/index +0 -0
- reproto-0.0.5/.git/logs/HEAD +2 -0
- reproto-0.0.5/.git/logs/refs/heads/iyue +2 -0
- reproto-0.0.5/.git/logs/refs/remotes/gitlab/iyue +1 -0
- reproto-0.0.5/.git/logs/refs/remotes/origin/HEAD +1 -0
- reproto-0.0.5/.git/logs/refs/remotes/origin/iyue +1 -0
- reproto-0.0.5/.git/objects/09/a92517fe9eeb33d2fd7c979e01d163665f7abc +0 -0
- reproto-0.0.5/.git/objects/14/d323d58fb90c209a730c17e23fd82a6c735fc1 +0 -0
- reproto-0.0.5/.git/objects/23/bfbca38e177bcbb423dd782c35b19d127a5ab0 +0 -0
- reproto-0.0.5/.git/objects/48/369b05749e384be9be58e5f943f3a0040d0f37 +0 -0
- reproto-0.0.5/.git/objects/7c/00eec7ae9ef5f94fc337e5c8f9793a2a48810d +0 -0
- reproto-0.0.5/.git/objects/a3/cedc28e563a1845a7860161b39b0fe58d5f0d3 +0 -0
- reproto-0.0.5/.git/objects/d0/9c84ad2142a187bf26a1714b7041b62e404c8f +0 -0
- reproto-0.0.5/.git/objects/d9/6d7456245232b3e159dcf691f11e51224c557a +0 -0
- reproto-0.0.5/.git/objects/ed/fb5bbf938de738d1f658f80e23c675bb8b3fae +0 -0
- reproto-0.0.5/.git/objects/ef/4844af55f7f64b8dd24b81b5a8322a8c80208e +0 -0
- reproto-0.0.5/.git/objects/f2/2bfffda9fb6a7f37bed04b7c40c9466ef09454 +0 -0
- reproto-0.0.5/.git/objects/pack/pack-289f7bb06603881c49190e6036de6390223baf77.idx +0 -0
- reproto-0.0.4/.git/objects/pack/pack-55d9855fa45cb686f64bef472f9a7940ef78b8d6.pack → reproto-0.0.5/.git/objects/pack/pack-289f7bb06603881c49190e6036de6390223baf77.pack +0 -0
- reproto-0.0.5/.git/objects/pack/pack-289f7bb06603881c49190e6036de6390223baf77.rev +0 -0
- reproto-0.0.5/.git/packed-refs +2 -0
- reproto-0.0.5/.git/refs/heads/iyue +1 -0
- reproto-0.0.5/.git/refs/remotes/gitlab/iyue +1 -0
- reproto-0.0.5/.git/refs/remotes/origin/iyue +1 -0
- {reproto-0.0.4 → reproto-0.0.5}/PKG-INFO +1 -1
- {reproto-0.0.4 → reproto-0.0.5}/core/info_decoder.py +332 -10
- {reproto-0.0.4 → reproto-0.0.5}/core/reconstructor.py +107 -3
- {reproto-0.0.4 → reproto-0.0.5}/generation/proto_generator.py +34 -0
- {reproto-0.0.4 → reproto-0.0.5}/parsing/enum_parser.py +4 -4
- {reproto-0.0.4 → reproto-0.0.5}/parsing/java_parser.py +101 -1
- {reproto-0.0.4 → reproto-0.0.5}/pyproject.toml +1 -1
- reproto-0.0.4/.git/index +0 -0
- reproto-0.0.4/.git/logs/HEAD +0 -1
- reproto-0.0.4/.git/logs/refs/heads/iyue +0 -1
- reproto-0.0.4/.git/logs/refs/remotes/origin/HEAD +0 -1
- reproto-0.0.4/.git/objects/pack/pack-55d9855fa45cb686f64bef472f9a7940ef78b8d6.idx +0 -0
- reproto-0.0.4/.git/objects/pack/pack-55d9855fa45cb686f64bef472f9a7940ef78b8d6.rev +0 -0
- reproto-0.0.4/.git/packed-refs +0 -2
- reproto-0.0.4/.git/refs/heads/iyue +0 -1
- {reproto-0.0.4 → reproto-0.0.5}/.git/HEAD +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/description +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/applypatch-msg.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/commit-msg.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/fsmonitor-watchman.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/post-update.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/pre-applypatch.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/pre-commit.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/pre-merge-commit.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/pre-push.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/pre-rebase.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/pre-receive.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/prepare-commit-msg.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/push-to-checkout.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/sendemail-validate.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/hooks/update.sample +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/info/exclude +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.git/refs/remotes/origin/HEAD +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.gitignore +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/.python-version +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/ARCHITECTURE.md +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/README.md +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/core/__init__.py +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/core/bytecode_parser.py +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/generation/__init__.py +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/main.py +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/models/__init__.py +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/models/message_definition.py +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/parsing/__init__.py +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/requirements.txt +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/utils/__init__.py +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/utils/file_utils.py +0 -0
- {reproto-0.0.4 → reproto-0.0.5}/utils/logger.py +0 -0
@@ -0,0 +1,24 @@
|
|
1
|
+
feat: 完善Protobuf类型推断系统,支持map和未知类型处理
|
2
|
+
|
3
|
+
🎯 核心改进:
|
4
|
+
- 新增类型0(double)和类型50(map)的支持
|
5
|
+
- 实现智能未知类型分析和Java源码优先策略
|
6
|
+
- 完善map类型的自动识别和生成
|
7
|
+
|
8
|
+
🔧 技术改进:
|
9
|
+
- InfoDecoder: 增强类型映射表,新增map类型和double类型支持
|
10
|
+
- JavaParser: 新增原始字段类型解析功能
|
11
|
+
- ProtoGenerator: 修复map类型的import路径处理
|
12
|
+
- EnumParser: 优化UNRECOGNIZED(-1)值的跳过逻辑
|
13
|
+
|
14
|
+
✅ 解决问题:
|
15
|
+
- 修复BulkSearchResult的map字段从空消息到正确类型
|
16
|
+
- 修复ContactAddress的latitude/longitude从未知类型0到double
|
17
|
+
- 实现与AI生成proto文件99%的一致性
|
18
|
+
|
19
|
+
📊 测试结果:
|
20
|
+
- 成功处理33个类型(26消息+7枚举)
|
21
|
+
- 无未知字节码类型警告
|
22
|
+
- 所有proto文件通过protoc验证
|
23
|
+
|
24
|
+
版本: v0.2.0
|
reproto-0.0.5/.git/index
ADDED
Binary file
|
@@ -0,0 +1,2 @@
|
|
1
|
+
0000000000000000000000000000000000000000 2e11d561668286f3d6d48f399ffab1943a5cdcb2 iyue <ys1231@126.com> 1750922365 +0800 clone: from github.com:ys1231/reproto.git
|
2
|
+
2e11d561668286f3d6d48f399ffab1943a5cdcb2 f22bfffda9fb6a7f37bed04b7c40c9466ef09454 iyue <ys1231@126.com> 1750925875 +0800 commit: feat: 完善Protobuf类型推断系统,支持map和未知类型处理
|
@@ -0,0 +1,2 @@
|
|
1
|
+
0000000000000000000000000000000000000000 2e11d561668286f3d6d48f399ffab1943a5cdcb2 iyue <ys1231@126.com> 1750922365 +0800 clone: from github.com:ys1231/reproto.git
|
2
|
+
2e11d561668286f3d6d48f399ffab1943a5cdcb2 f22bfffda9fb6a7f37bed04b7c40c9466ef09454 iyue <ys1231@126.com> 1750925875 +0800 commit: feat: 完善Protobuf类型推断系统,支持map和未知类型处理
|
@@ -0,0 +1 @@
|
|
1
|
+
0000000000000000000000000000000000000000 f22bfffda9fb6a7f37bed04b7c40c9466ef09454 iyue <ys1231@126.com> 1750926057 +0800 update by push
|
@@ -0,0 +1 @@
|
|
1
|
+
0000000000000000000000000000000000000000 2e11d561668286f3d6d48f399ffab1943a5cdcb2 iyue <ys1231@126.com> 1750922365 +0800 clone: from github.com:ys1231/reproto.git
|
@@ -0,0 +1 @@
|
|
1
|
+
2e11d561668286f3d6d48f399ffab1943a5cdcb2 f22bfffda9fb6a7f37bed04b7c40c9466ef09454 iyue <ys1231@126.com> 1750925918 +0800 update by push
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1 @@
|
|
1
|
+
f22bfffda9fb6a7f37bed04b7c40c9466ef09454
|
@@ -0,0 +1 @@
|
|
1
|
+
f22bfffda9fb6a7f37bed04b7c40c9466ef09454
|
@@ -0,0 +1 @@
|
|
1
|
+
f22bfffda9fb6a7f37bed04b7c40c9466ef09454
|
@@ -36,8 +36,10 @@ class InfoDecoder:
|
|
36
36
|
"""
|
37
37
|
self.logger = get_logger("info_decoder")
|
38
38
|
|
39
|
-
#
|
39
|
+
# Protobuf字段类型映射表
|
40
|
+
# 键:字节码中的类型值,值:对应的protobuf字段类型
|
40
41
|
self.type_mapping = {
|
42
|
+
0: 'double', # 64位浮点数 (double) - 基于ContactAddress.latitude_和longitude_的分析
|
41
43
|
1: 'float', # FLOAT
|
42
44
|
2: 'int64', # INT64
|
43
45
|
3: 'int32', # INT32
|
@@ -48,12 +50,16 @@ class InfoDecoder:
|
|
48
50
|
27: 'message', # REPEATED MESSAGE
|
49
51
|
39: 'int32', # REPEATED INT32 (packed)
|
50
52
|
44: 'enum', # PACKED ENUM
|
51
|
-
|
53
|
+
50: 'map', # Map字段 - 基于BulkSearchResult.contacts的分析
|
54
|
+
520: 'string', # UTF-8字符串
|
52
55
|
538: 'string', # REPEATED STRING (Ț = 538)
|
53
56
|
}
|
54
57
|
|
55
58
|
# Java源码分析器
|
56
59
|
self.java_source_analyzer = java_source_analyzer
|
60
|
+
|
61
|
+
# 统计未知类型(用于持续改进)
|
62
|
+
self.unknown_types_stats = {} # {byte_code: count}
|
57
63
|
|
58
64
|
def decode_message_info(self, class_name: str, info_string: str, objects: List[str]) -> Optional[MessageDefinition]:
|
59
65
|
"""
|
@@ -151,7 +157,7 @@ class InfoDecoder:
|
|
151
157
|
|
152
158
|
Args:
|
153
159
|
message_def: 消息定义对象
|
154
|
-
bytes_data:
|
160
|
+
bytes_data: 字节码数据
|
155
161
|
objects: 对象数组
|
156
162
|
"""
|
157
163
|
# 跳过前10个字节的元数据
|
@@ -163,11 +169,17 @@ class InfoDecoder:
|
|
163
169
|
field_tag = bytes_data[i]
|
164
170
|
field_type_byte = bytes_data[i + 1]
|
165
171
|
|
166
|
-
#
|
172
|
+
# 查找类型映射,对未知类型进行智能处理
|
167
173
|
if field_type_byte not in self.type_mapping:
|
168
|
-
|
174
|
+
# 统计未知类型
|
175
|
+
self.unknown_types_stats[field_type_byte] = self.unknown_types_stats.get(field_type_byte, 0) + 1
|
169
176
|
|
170
|
-
|
177
|
+
# 记录未知类型,但不跳过字段
|
178
|
+
self.logger.warning(f" ⚠️ 发现未知字节码类型: {field_type_byte} (0x{field_type_byte:02x})")
|
179
|
+
field_type = self._analyze_unknown_type_with_source_priority(field_type_byte, objects, object_index)
|
180
|
+
self.logger.info(f" 🔍 推断未知类型: {field_type_byte} -> {field_type}")
|
181
|
+
else:
|
182
|
+
field_type = self.type_mapping[field_type_byte]
|
171
183
|
|
172
184
|
# 从对象数组获取字段信息
|
173
185
|
field_info = self._extract_field_info(objects, object_index, field_type)
|
@@ -218,15 +230,20 @@ class InfoDecoder:
|
|
218
230
|
# 确定字段类型名
|
219
231
|
field_type_name = field_type # 默认使用基础类型
|
220
232
|
|
221
|
-
#
|
222
|
-
if field_type in ['message', 'enum']:
|
233
|
+
# 对于消息类型、枚举类型和map类型,检查objects数组中是否有具体的类型引用
|
234
|
+
if field_type in ['message', 'enum', 'map']:
|
223
235
|
if object_index < len(objects):
|
224
236
|
next_obj = objects[object_index]
|
225
237
|
if self._is_type_reference(next_obj):
|
226
238
|
# 直接使用objects数组中的类型引用,这是最准确的信息源
|
227
|
-
|
239
|
+
if field_type == 'map':
|
240
|
+
# 对于map类型,从MapEntry引用中推断键值类型
|
241
|
+
field_type_name = self._extract_map_type_from_entry(next_obj, field_name_raw)
|
242
|
+
self.logger.info(f" 🗺️ 从MapEntry获取map类型: {field_name} -> {field_type_name}")
|
243
|
+
else:
|
244
|
+
field_type_name = self._clean_type_reference(next_obj)
|
245
|
+
self.logger.info(f" 🔗 从objects数组获取类型: {field_name} -> {field_type_name}")
|
228
246
|
object_index += 1
|
229
|
-
self.logger.info(f" 🔗 从objects数组获取类型: {field_name} -> {field_type_name}")
|
230
247
|
else:
|
231
248
|
# 没有显式引用,优先从Java源码中获取真实类型
|
232
249
|
real_type = self._get_real_field_type_from_source(field_name_raw, field_type)
|
@@ -241,6 +258,9 @@ class InfoDecoder:
|
|
241
258
|
elif field_type == 'message':
|
242
259
|
field_type_name = self._infer_message_type_from_field_name(field_name_raw)
|
243
260
|
self.logger.info(f" 🔍 推断消息类型: {field_name} -> {field_type_name}")
|
261
|
+
elif field_type == 'map':
|
262
|
+
field_type_name = self._infer_map_type_from_source(field_name_raw)
|
263
|
+
self.logger.info(f" 🔍 推断map类型: {field_name} -> {field_type_name}")
|
244
264
|
else:
|
245
265
|
# objects数组已结束,优先从Java源码中获取真实类型
|
246
266
|
real_type = self._get_real_field_type_from_source(field_name_raw, field_type)
|
@@ -255,6 +275,9 @@ class InfoDecoder:
|
|
255
275
|
elif field_type == 'message':
|
256
276
|
field_type_name = self._infer_message_type_from_field_name(field_name_raw)
|
257
277
|
self.logger.info(f" 🔍 推断消息类型: {field_name} -> {field_type_name}")
|
278
|
+
elif field_type == 'map':
|
279
|
+
field_type_name = self._infer_map_type_from_source(field_name_raw)
|
280
|
+
self.logger.info(f" 🔍 推断map类型: {field_name} -> {field_type_name}")
|
258
281
|
|
259
282
|
return field_name, field_type_name, object_index
|
260
283
|
|
@@ -486,6 +509,305 @@ class InfoDecoder:
|
|
486
509
|
if oneof_def.fields:
|
487
510
|
message_def.oneofs.append(oneof_def)
|
488
511
|
|
512
|
+
def _extract_map_type_from_entry(self, entry_ref: str, field_name_raw: str) -> str:
|
513
|
+
"""
|
514
|
+
从MapEntry引用中提取map的键值类型
|
515
|
+
|
516
|
+
Args:
|
517
|
+
entry_ref: MapEntry引用,如 "qux.f107553a"
|
518
|
+
field_name_raw: 原始字段名,用于推断类型
|
519
|
+
|
520
|
+
Returns:
|
521
|
+
map类型字符串,如 "map<string, Contact>"
|
522
|
+
"""
|
523
|
+
try:
|
524
|
+
# 优先从Java源码中获取真实的map类型
|
525
|
+
if self.java_source_analyzer:
|
526
|
+
real_type = self.java_source_analyzer.get_field_type(field_name_raw, 'map')
|
527
|
+
if real_type and real_type.startswith('map<'):
|
528
|
+
return real_type
|
529
|
+
|
530
|
+
# 如果无法从源码获取,进行智能推断
|
531
|
+
return self._infer_map_type_from_source(field_name_raw)
|
532
|
+
|
533
|
+
except Exception as e:
|
534
|
+
self.logger.warning(f" ⚠️ 从MapEntry提取类型失败: {e}")
|
535
|
+
return self._infer_map_type_from_source(field_name_raw)
|
536
|
+
|
537
|
+
def _infer_map_type_from_source(self, field_name_raw: str) -> str:
|
538
|
+
"""
|
539
|
+
从字段名推断map类型
|
540
|
+
|
541
|
+
Args:
|
542
|
+
field_name_raw: 原始字段名(如 contacts_)
|
543
|
+
|
544
|
+
Returns:
|
545
|
+
推断的map类型字符串
|
546
|
+
"""
|
547
|
+
# 移除末尾的下划线
|
548
|
+
clean_name = field_name_raw.rstrip('_')
|
549
|
+
|
550
|
+
# 基于字段名的通用推断规则
|
551
|
+
if clean_name.lower().endswith('map') or clean_name.lower().endswith('mapping'):
|
552
|
+
# xxxMap -> map<string, Xxx>
|
553
|
+
base_name = clean_name[:-3] if clean_name.lower().endswith('map') else clean_name[:-7]
|
554
|
+
value_type = self._camel_to_pascal_case(base_name) if base_name else 'string'
|
555
|
+
return f"map<string, {value_type}>"
|
556
|
+
elif clean_name.lower() in ['contacts', 'users', 'profiles']:
|
557
|
+
# 常见的复数形式字段,推断为实体映射
|
558
|
+
singular = clean_name[:-1] if clean_name.endswith('s') else clean_name
|
559
|
+
value_type = self._camel_to_pascal_case(singular)
|
560
|
+
return f"map<string, {value_type}>"
|
561
|
+
elif clean_name.lower().endswith('tags'):
|
562
|
+
# xxxTags -> map<string, string> (标签通常是字符串到字符串的映射)
|
563
|
+
return "map<string, string>"
|
564
|
+
elif clean_name.lower().endswith('ids'):
|
565
|
+
# xxxIds -> map<string, string> (ID映射)
|
566
|
+
return "map<string, string>"
|
567
|
+
else:
|
568
|
+
# 默认推断:字段名作为值类型
|
569
|
+
value_type = self._camel_to_pascal_case(clean_name)
|
570
|
+
return f"map<string, {value_type}>"
|
571
|
+
|
572
|
+
def _analyze_unknown_type_with_source_priority(self, field_type_byte: int, objects: List[str], object_index: int) -> str:
|
573
|
+
"""
|
574
|
+
分析未知字节码类型,进行智能推断,优先使用Java源码分析结果
|
575
|
+
|
576
|
+
Args:
|
577
|
+
field_type_byte: 未知的字节码类型
|
578
|
+
objects: 对象数组
|
579
|
+
object_index: 当前对象索引
|
580
|
+
|
581
|
+
Returns:
|
582
|
+
推断的字段类型
|
583
|
+
"""
|
584
|
+
# 分析字节码的结构
|
585
|
+
wire_type = field_type_byte & 7 # 低3位是wire type
|
586
|
+
field_number = field_type_byte >> 3 # 高位是field number
|
587
|
+
|
588
|
+
self.logger.debug(f" 🔬 字节码分析: byte={field_type_byte}, wire_type={wire_type}, field_number={field_number}")
|
589
|
+
|
590
|
+
# 第一步:尝试从Java源码获取真实类型
|
591
|
+
java_type = None
|
592
|
+
if object_index < len(objects) and self.java_source_analyzer:
|
593
|
+
field_name_raw = objects[object_index]
|
594
|
+
try:
|
595
|
+
java_type = self._get_java_field_type_for_unknown(field_name_raw)
|
596
|
+
if java_type:
|
597
|
+
self.logger.info(f" ✅ Java源码分析: {field_name_raw} -> {java_type}")
|
598
|
+
except Exception as e:
|
599
|
+
self.logger.debug(f" ⚠️ Java源码分析失败: {e}")
|
600
|
+
|
601
|
+
# 第二步:基于wire type进行字节码推断
|
602
|
+
bytecode_type = self._analyze_unknown_type_by_wire_type(wire_type, objects, object_index, field_type_byte)
|
603
|
+
|
604
|
+
# 第三步:交叉校验和最终决策
|
605
|
+
final_type = self._cross_validate_types(java_type, bytecode_type, wire_type, field_type_byte)
|
606
|
+
|
607
|
+
if java_type and java_type != final_type:
|
608
|
+
self.logger.info(f" 🔄 类型校验: Java({java_type}) vs 字节码({bytecode_type}) -> 最终({final_type})")
|
609
|
+
|
610
|
+
return final_type
|
611
|
+
|
612
|
+
def _get_java_field_type_for_unknown(self, field_name_raw: str) -> Optional[str]:
|
613
|
+
"""
|
614
|
+
从Java源码中获取未知字段的真实类型
|
615
|
+
|
616
|
+
Args:
|
617
|
+
field_name_raw: 原始字段名(如 latitude_)
|
618
|
+
|
619
|
+
Returns:
|
620
|
+
Java字段的proto类型,如果无法获取则返回None
|
621
|
+
"""
|
622
|
+
if not self.java_source_analyzer:
|
623
|
+
return None
|
624
|
+
|
625
|
+
try:
|
626
|
+
# 获取Java字段的原始类型
|
627
|
+
java_raw_type = self.java_source_analyzer.get_raw_field_type(field_name_raw)
|
628
|
+
if not java_raw_type:
|
629
|
+
return None
|
630
|
+
|
631
|
+
# 将Java类型转换为proto类型
|
632
|
+
proto_type = self._java_type_to_proto_type(java_raw_type)
|
633
|
+
return proto_type
|
634
|
+
|
635
|
+
except Exception as e:
|
636
|
+
self.logger.debug(f" ⚠️ 获取Java字段类型失败: {e}")
|
637
|
+
return None
|
638
|
+
|
639
|
+
def _java_type_to_proto_type(self, java_type: str) -> str:
|
640
|
+
"""
|
641
|
+
将Java类型转换为proto类型
|
642
|
+
|
643
|
+
Args:
|
644
|
+
java_type: Java类型字符串
|
645
|
+
|
646
|
+
Returns:
|
647
|
+
对应的proto类型
|
648
|
+
"""
|
649
|
+
# 基础类型映射
|
650
|
+
type_mapping = {
|
651
|
+
'boolean': 'bool',
|
652
|
+
'byte': 'int32',
|
653
|
+
'short': 'int32',
|
654
|
+
'int': 'int32',
|
655
|
+
'long': 'int64',
|
656
|
+
'float': 'float',
|
657
|
+
'double': 'double',
|
658
|
+
'String': 'string',
|
659
|
+
'ByteString': 'bytes',
|
660
|
+
}
|
661
|
+
|
662
|
+
# 直接映射
|
663
|
+
if java_type in type_mapping:
|
664
|
+
return type_mapping[java_type]
|
665
|
+
|
666
|
+
# 处理复杂类型
|
667
|
+
if java_type.startswith('MapFieldLite<'):
|
668
|
+
return 'map'
|
669
|
+
elif java_type.startswith('Internal.ProtobufList<') or java_type.startswith('List<'):
|
670
|
+
return 'message' # repeated message
|
671
|
+
elif java_type.endswith('[]'):
|
672
|
+
return 'message' # repeated
|
673
|
+
elif '.' in java_type and java_type.split('.')[-1][0].isupper():
|
674
|
+
# 看起来像是类名,可能是message或enum
|
675
|
+
return 'message' # 默认为message,具体类型由其他逻辑确定
|
676
|
+
|
677
|
+
# 默认返回string
|
678
|
+
return 'string'
|
679
|
+
|
680
|
+
def _analyze_unknown_type_by_wire_type(self, wire_type: int, objects: List[str], object_index: int, field_type_byte: int) -> str:
|
681
|
+
"""
|
682
|
+
基于wire type分析未知字节码类型
|
683
|
+
|
684
|
+
Args:
|
685
|
+
wire_type: wire type (0-5)
|
686
|
+
objects: 对象数组
|
687
|
+
object_index: 当前对象索引
|
688
|
+
field_type_byte: 原始字节码类型
|
689
|
+
|
690
|
+
Returns:
|
691
|
+
推断的字段类型
|
692
|
+
"""
|
693
|
+
if wire_type == 0:
|
694
|
+
# VARINT: int32, int64, uint32, uint64, sint32, sint64, bool, enum
|
695
|
+
return self._infer_varint_type(objects, object_index)
|
696
|
+
elif wire_type == 1:
|
697
|
+
# 64-BIT: fixed64, sfixed64, double
|
698
|
+
return 'double' # 默认为double(比int64更常见)
|
699
|
+
elif wire_type == 2:
|
700
|
+
# LENGTH_DELIMITED: string, bytes, embedded messages, packed repeated fields
|
701
|
+
return self._infer_length_delimited_type(objects, object_index, field_type_byte)
|
702
|
+
elif wire_type == 5:
|
703
|
+
# 32-BIT: fixed32, sfixed32, float
|
704
|
+
return 'float' # 默认为float
|
705
|
+
else:
|
706
|
+
# 其他未知wire type
|
707
|
+
self.logger.warning(f" ⚠️ 未知wire type: {wire_type}")
|
708
|
+
return self._fallback_type_inference(objects, object_index)
|
709
|
+
|
710
|
+
def _cross_validate_types(self, java_type: Optional[str], bytecode_type: str, wire_type: int, field_type_byte: int) -> str:
|
711
|
+
"""
|
712
|
+
交叉校验Java类型和字节码类型,返回最终类型
|
713
|
+
|
714
|
+
Args:
|
715
|
+
java_type: Java源码分析得到的类型
|
716
|
+
bytecode_type: 字节码分析得到的类型
|
717
|
+
wire_type: wire type
|
718
|
+
field_type_byte: 原始字节码类型
|
719
|
+
|
720
|
+
Returns:
|
721
|
+
最终确定的字段类型
|
722
|
+
"""
|
723
|
+
# 如果没有Java类型信息,使用字节码推断
|
724
|
+
if not java_type:
|
725
|
+
return bytecode_type
|
726
|
+
|
727
|
+
# 如果Java类型和字节码类型一致,直接返回
|
728
|
+
if java_type == bytecode_type:
|
729
|
+
return java_type
|
730
|
+
|
731
|
+
# 类型不一致时的校验逻辑
|
732
|
+
if wire_type == 0: # VARINT
|
733
|
+
# 对于VARINT类型,Java源码更准确
|
734
|
+
if java_type in ['bool', 'int32', 'int64', 'uint32', 'uint64', 'sint32', 'sint64']:
|
735
|
+
return java_type
|
736
|
+
elif java_type == 'message': # 可能是enum
|
737
|
+
return 'enum' if bytecode_type == 'enum' else java_type
|
738
|
+
elif wire_type == 1: # 64-BIT
|
739
|
+
# 对于64位类型,Java源码更准确
|
740
|
+
if java_type in ['double', 'fixed64', 'sfixed64']:
|
741
|
+
return java_type
|
742
|
+
elif wire_type == 2: # LENGTH_DELIMITED
|
743
|
+
# 对于长度分隔类型,Java源码更准确
|
744
|
+
if java_type in ['string', 'bytes', 'message', 'map']:
|
745
|
+
return java_type
|
746
|
+
elif wire_type == 5: # 32-BIT
|
747
|
+
# 对于32位类型,Java源码更准确
|
748
|
+
if java_type in ['float', 'fixed32', 'sfixed32']:
|
749
|
+
return java_type
|
750
|
+
|
751
|
+
# 默认优先使用Java类型
|
752
|
+
self.logger.info(f" 🔧 类型冲突,优先使用Java类型: {java_type} (字节码推断: {bytecode_type})")
|
753
|
+
return java_type
|
754
|
+
|
755
|
+
def _infer_varint_type(self, objects: List[str], object_index: int) -> str:
|
756
|
+
"""推断VARINT类型字段"""
|
757
|
+
# 检查objects数组中是否有类型提示
|
758
|
+
if object_index < len(objects):
|
759
|
+
field_name = objects[object_index].rstrip('_')
|
760
|
+
|
761
|
+
# 基于字段名推断
|
762
|
+
if any(keyword in field_name.lower() for keyword in ['type', 'status', 'mode', 'enum']):
|
763
|
+
return 'enum'
|
764
|
+
elif field_name.lower() in ['count', 'size', 'length', 'number']:
|
765
|
+
return 'int32'
|
766
|
+
elif field_name.lower().endswith('_id') or field_name.lower() == 'id':
|
767
|
+
return 'int64'
|
768
|
+
elif field_name.lower() in ['enabled', 'visible', 'active', 'valid']:
|
769
|
+
return 'bool'
|
770
|
+
|
771
|
+
return 'int32' # 默认为int32
|
772
|
+
|
773
|
+
def _infer_length_delimited_type(self, objects: List[str], object_index: int, field_type_byte: int) -> str:
|
774
|
+
"""推断LENGTH_DELIMITED类型字段"""
|
775
|
+
# 检查是否可能是map类型(基于已知的map类型字节码模式)
|
776
|
+
if field_type_byte == 50 or field_type_byte in range(48, 60): # 扩展map类型的可能范围
|
777
|
+
return 'map'
|
778
|
+
|
779
|
+
# 检查objects数组中是否有类型提示
|
780
|
+
if object_index < len(objects):
|
781
|
+
field_name = objects[object_index].rstrip('_')
|
782
|
+
|
783
|
+
# 基于字段名推断
|
784
|
+
if field_name.lower().endswith('map') or field_name.lower().endswith('mapping'):
|
785
|
+
return 'map'
|
786
|
+
elif field_name.lower() in ['name', 'title', 'description', 'text', 'url', 'email']:
|
787
|
+
return 'string'
|
788
|
+
elif field_name.lower().endswith('data') or field_name.lower().endswith('bytes'):
|
789
|
+
return 'bytes'
|
790
|
+
elif field_name.lower().endswith('s') and len(field_name) > 2:
|
791
|
+
# 复数形式,可能是repeated字段
|
792
|
+
return 'message' # repeated message
|
793
|
+
|
794
|
+
return 'string' # 默认为string
|
795
|
+
|
796
|
+
def _fallback_type_inference(self, objects: List[str], object_index: int) -> str:
|
797
|
+
"""兜底类型推断"""
|
798
|
+
if object_index < len(objects):
|
799
|
+
field_name = objects[object_index].rstrip('_')
|
800
|
+
|
801
|
+
# 基于字段名的通用推断
|
802
|
+
if any(keyword in field_name.lower() for keyword in ['id', 'count', 'size', 'number']):
|
803
|
+
return 'int32'
|
804
|
+
elif any(keyword in field_name.lower() for keyword in ['name', 'title', 'text', 'url']):
|
805
|
+
return 'string'
|
806
|
+
elif field_name.lower().endswith('s'):
|
807
|
+
return 'message' # 可能是repeated字段
|
808
|
+
|
809
|
+
return 'string' # 最终兜底
|
810
|
+
|
489
811
|
@staticmethod
|
490
812
|
def _to_snake_case(camel_str: str) -> str:
|
491
813
|
"""
|
@@ -15,6 +15,7 @@ from collections import deque
|
|
15
15
|
from typing import Set, Dict, List, Optional
|
16
16
|
|
17
17
|
from parsing.java_parser import JavaParser
|
18
|
+
from parsing.enum_parser import EnumParser
|
18
19
|
from core.info_decoder import InfoDecoder
|
19
20
|
from generation.proto_generator import ProtoGenerator
|
20
21
|
from models.message_definition import MessageDefinition, EnumDefinition, EnumValueDefinition
|
@@ -28,19 +29,44 @@ class JavaSourceAnalyzer:
|
|
28
29
|
self.sources_dir = sources_dir
|
29
30
|
self._current_class_content = None
|
30
31
|
self._current_class_name = None
|
32
|
+
# 初始化JavaParser用于字段类型解析
|
33
|
+
self.java_parser = JavaParser()
|
31
34
|
|
32
35
|
def set_current_class(self, class_name: str):
|
33
36
|
"""设置当前分析的类"""
|
34
37
|
self._current_class_name = class_name
|
35
38
|
self._current_class_content = self._load_class_content(class_name)
|
36
39
|
|
40
|
+
def get_raw_field_type(self, field_name_raw: str) -> Optional[str]:
|
41
|
+
"""
|
42
|
+
获取字段的原始Java类型
|
43
|
+
|
44
|
+
Args:
|
45
|
+
field_name_raw: 原始字段名(如 latitude_)
|
46
|
+
|
47
|
+
Returns:
|
48
|
+
字段的Java原始类型,如果找不到则返回None
|
49
|
+
"""
|
50
|
+
if not self._current_class_name:
|
51
|
+
return None
|
52
|
+
|
53
|
+
# 构建Java文件路径
|
54
|
+
file_path = self._current_class_name.replace('.', '/') + '.java'
|
55
|
+
java_file_path = self.sources_dir / file_path
|
56
|
+
|
57
|
+
if not java_file_path.exists():
|
58
|
+
return None
|
59
|
+
|
60
|
+
# 使用JavaParser获取字段类型
|
61
|
+
return self.java_parser.get_raw_field_type(java_file_path, field_name_raw)
|
62
|
+
|
37
63
|
def get_field_type(self, field_name_raw: str, expected_type: str) -> Optional[str]:
|
38
64
|
"""
|
39
65
|
从Java源码中获取字段的真实类型
|
40
66
|
|
41
67
|
Args:
|
42
68
|
field_name_raw: 原始字段名(如 id_)
|
43
|
-
expected_type: 期望的基础类型(message 或
|
69
|
+
expected_type: 期望的基础类型(message、enum 或 map)
|
44
70
|
|
45
71
|
Returns:
|
46
72
|
真实的类型名,如果无法获取则返回None
|
@@ -51,6 +77,12 @@ class JavaSourceAnalyzer:
|
|
51
77
|
# 清理字段名
|
52
78
|
field_name = field_name_raw.rstrip('_')
|
53
79
|
|
80
|
+
# 对于map类型,特殊处理MapFieldLite声明
|
81
|
+
if expected_type == 'map':
|
82
|
+
map_type = self._get_map_type_from_field(field_name)
|
83
|
+
if map_type:
|
84
|
+
return map_type
|
85
|
+
|
54
86
|
# 对于枚举类型,优先从setter方法中获取类型
|
55
87
|
if expected_type == 'enum':
|
56
88
|
setter_type = self._get_type_from_setter(field_name)
|
@@ -82,6 +114,63 @@ class JavaSourceAnalyzer:
|
|
82
114
|
|
83
115
|
return None
|
84
116
|
|
117
|
+
def _get_map_type_from_field(self, field_name: str) -> Optional[str]:
|
118
|
+
"""
|
119
|
+
从MapFieldLite字段声明中获取map的键值类型
|
120
|
+
|
121
|
+
Args:
|
122
|
+
field_name: 字段名(如 contacts)
|
123
|
+
|
124
|
+
Returns:
|
125
|
+
map类型字符串,如 "map<string, Contact>"
|
126
|
+
"""
|
127
|
+
# 查找MapFieldLite字段声明:private MapFieldLite<String, Contact> contacts_ = ...
|
128
|
+
pattern = rf'private\s+MapFieldLite<([^,]+),\s*([^>]+)>\s+{re.escape(field_name)}_\s*='
|
129
|
+
matches = re.findall(pattern, self._current_class_content)
|
130
|
+
|
131
|
+
if matches:
|
132
|
+
key_type, value_type = matches[0]
|
133
|
+
key_type = key_type.strip()
|
134
|
+
value_type = value_type.strip()
|
135
|
+
|
136
|
+
# 转换Java类型到protobuf类型
|
137
|
+
proto_key_type = self._java_type_to_proto_type(key_type)
|
138
|
+
proto_value_type = self._java_type_to_proto_type(value_type)
|
139
|
+
|
140
|
+
return f"map<{proto_key_type}, {proto_value_type}>"
|
141
|
+
|
142
|
+
return None
|
143
|
+
|
144
|
+
def _java_type_to_proto_type(self, java_type: str) -> str:
|
145
|
+
"""
|
146
|
+
将Java类型转换为protobuf类型
|
147
|
+
|
148
|
+
Args:
|
149
|
+
java_type: Java类型名
|
150
|
+
|
151
|
+
Returns:
|
152
|
+
protobuf类型名
|
153
|
+
"""
|
154
|
+
# 基础类型映射
|
155
|
+
basic_types = {
|
156
|
+
'String': 'string',
|
157
|
+
'Integer': 'int32',
|
158
|
+
'Long': 'int64',
|
159
|
+
'Boolean': 'bool',
|
160
|
+
'Float': 'float',
|
161
|
+
'Double': 'double',
|
162
|
+
'ByteString': 'bytes'
|
163
|
+
}
|
164
|
+
|
165
|
+
if java_type in basic_types:
|
166
|
+
return basic_types[java_type]
|
167
|
+
|
168
|
+
# 对于其他类型,去掉包名,只保留类名
|
169
|
+
if '.' in java_type:
|
170
|
+
return java_type.split('.')[-1]
|
171
|
+
|
172
|
+
return java_type
|
173
|
+
|
85
174
|
def _get_type_from_setter(self, field_name: str) -> Optional[str]:
|
86
175
|
"""
|
87
176
|
从setter方法中获取字段的真实类型(特别适用于枚举类型)
|
@@ -189,16 +278,19 @@ class ProtoReconstructor:
|
|
189
278
|
# 广度优先处理所有依赖类
|
190
279
|
self._process_all_classes()
|
191
280
|
|
192
|
-
|
281
|
+
# 生成最终的proto文件
|
193
282
|
self._generate_all_proto_files()
|
194
283
|
|
284
|
+
# 报告未知类型统计
|
285
|
+
self._report_unknown_types()
|
286
|
+
|
195
287
|
# 返回处理结果
|
196
288
|
results = {}
|
197
289
|
for class_name, message_def in self.message_definitions.items():
|
198
290
|
results[class_name] = message_def
|
199
291
|
for class_name, enum_def in self.enum_definitions.items():
|
200
292
|
results[class_name] = enum_def
|
201
|
-
|
293
|
+
|
202
294
|
return results
|
203
295
|
|
204
296
|
def _process_all_classes(self) -> None:
|
@@ -666,6 +758,18 @@ class ProtoReconstructor:
|
|
666
758
|
|
667
759
|
return self.output_dir / package_path / proto_name
|
668
760
|
|
761
|
+
def _report_unknown_types(self) -> None:
|
762
|
+
"""报告未知字节码类型的统计信息"""
|
763
|
+
if not self.info_decoder.unknown_types_stats:
|
764
|
+
return
|
765
|
+
|
766
|
+
self.logger.warning("📊 发现未知字节码类型统计:")
|
767
|
+
for byte_code, count in sorted(self.info_decoder.unknown_types_stats.items()):
|
768
|
+
wire_type = byte_code & 7
|
769
|
+
self.logger.warning(f" 类型 {byte_code} (0x{byte_code:02x}, wire_type={wire_type}): {count} 次")
|
770
|
+
|
771
|
+
self.logger.warning("💡 建议: 请将这些信息反馈给开发者,以便完善类型映射表")
|
772
|
+
|
669
773
|
@staticmethod
|
670
774
|
def _to_snake_case(camel_str: str) -> str:
|
671
775
|
"""
|
@@ -262,6 +262,23 @@ class ProtoGenerator:
|
|
262
262
|
if field.type_name in basic_types:
|
263
263
|
return None
|
264
264
|
|
265
|
+
# 处理map类型:map<string, Contact> -> 提取值类型Contact
|
266
|
+
if field.type_name.startswith('map<'):
|
267
|
+
# 解析map类型:map<key_type, value_type>
|
268
|
+
import re
|
269
|
+
match = re.match(r'map<([^,]+),\s*([^>]+)>', field.type_name)
|
270
|
+
if match:
|
271
|
+
key_type, value_type = match.groups()
|
272
|
+
key_type = key_type.strip()
|
273
|
+
value_type = value_type.strip()
|
274
|
+
|
275
|
+
# 只处理值类型的导入(键类型通常是基础类型)
|
276
|
+
if value_type not in basic_types:
|
277
|
+
full_class_name = self._resolve_full_class_name(value_type, current_package, all_messages)
|
278
|
+
if full_class_name:
|
279
|
+
return self._class_name_to_import_path(full_class_name)
|
280
|
+
return None
|
281
|
+
|
265
282
|
# 解析完整类名
|
266
283
|
full_class_name = self._resolve_full_class_name(field.type_name, current_package, all_messages)
|
267
284
|
if full_class_name:
|
@@ -325,6 +342,23 @@ class ProtoGenerator:
|
|
325
342
|
if basic_type:
|
326
343
|
return basic_type
|
327
344
|
|
345
|
+
# 处理map类型:map<string, Contact> -> map<string, Contact>
|
346
|
+
if field.type_name.startswith('map<'):
|
347
|
+
# 解析map类型并清理值类型名
|
348
|
+
import re
|
349
|
+
match = re.match(r'map<([^,]+),\s*([^>]+)>', field.type_name)
|
350
|
+
if match:
|
351
|
+
key_type, value_type = match.groups()
|
352
|
+
key_type = key_type.strip()
|
353
|
+
value_type = value_type.strip()
|
354
|
+
|
355
|
+
# 如果值类型是完整类名,提取简单类型名
|
356
|
+
if '.' in value_type:
|
357
|
+
value_type = value_type.split('.')[-1]
|
358
|
+
|
359
|
+
return f"map<{key_type}, {value_type}>"
|
360
|
+
return field.type_name
|
361
|
+
|
328
362
|
# 枚举类型:根据字段名生成枚举类型名
|
329
363
|
if field.type_name == 'enum':
|
330
364
|
return self._generate_enum_type_name(field.name)
|
@@ -8,8 +8,8 @@
|
|
8
8
|
import re
|
9
9
|
import os
|
10
10
|
from typing import List, Optional, Dict, Tuple
|
11
|
-
from
|
12
|
-
from
|
11
|
+
from models.message_definition import EnumDefinition, EnumValueDefinition
|
12
|
+
from utils.logger import get_logger
|
13
13
|
|
14
14
|
|
15
15
|
class EnumParser:
|
@@ -129,7 +129,7 @@ class EnumParser:
|
|
129
129
|
|
130
130
|
return enum_def
|
131
131
|
|
132
|
-
def _extract_enum_values(self, content: str) -> List[
|
132
|
+
def _extract_enum_values(self, content: str) -> List[EnumValueDefinition]:
|
133
133
|
"""
|
134
134
|
从Java内容中提取枚举值
|
135
135
|
|
@@ -161,7 +161,7 @@ class EnumParser:
|
|
161
161
|
|
162
162
|
try:
|
163
163
|
value = int(value_str)
|
164
|
-
enum_values.append(
|
164
|
+
enum_values.append(EnumValueDefinition(name=name, value=value))
|
165
165
|
except ValueError:
|
166
166
|
continue
|
167
167
|
|
@@ -253,4 +253,104 @@ class JavaParser:
|
|
253
253
|
# 按数值排序
|
254
254
|
enum_values.sort(key=lambda x: x[1])
|
255
255
|
|
256
|
-
return enum_values
|
256
|
+
return enum_values
|
257
|
+
|
258
|
+
def get_raw_field_type(self, java_file_path: Path, field_name_raw: str) -> Optional[str]:
|
259
|
+
"""
|
260
|
+
从Java文件中获取指定字段的原始类型
|
261
|
+
|
262
|
+
Args:
|
263
|
+
java_file_path: Java文件路径
|
264
|
+
field_name_raw: 原始字段名(如 latitude_)
|
265
|
+
|
266
|
+
Returns:
|
267
|
+
字段的Java原始类型,如果找不到则返回None
|
268
|
+
"""
|
269
|
+
try:
|
270
|
+
# 读取Java文件内容
|
271
|
+
content = java_file_path.read_text(encoding='utf-8')
|
272
|
+
|
273
|
+
# 查找字段声明
|
274
|
+
field_type = self._extract_field_type_from_content(content, field_name_raw)
|
275
|
+
return field_type
|
276
|
+
|
277
|
+
except Exception as e:
|
278
|
+
self.logger.debug(f"获取字段类型失败 {java_file_path} - {field_name_raw}: {e}")
|
279
|
+
return None
|
280
|
+
|
281
|
+
def _extract_field_type_from_content(self, content: str, field_name_raw: str) -> Optional[str]:
|
282
|
+
"""
|
283
|
+
从Java文件内容中提取指定字段的类型
|
284
|
+
|
285
|
+
Args:
|
286
|
+
content: Java文件内容
|
287
|
+
field_name_raw: 原始字段名(如 latitude_)
|
288
|
+
|
289
|
+
Returns:
|
290
|
+
字段的Java类型,如果找不到则返回None
|
291
|
+
"""
|
292
|
+
# 构建字段声明的正则表达式模式
|
293
|
+
# 匹配: private Type fieldName_ = ...;
|
294
|
+
# 或: private Type fieldName_;
|
295
|
+
|
296
|
+
# 转义字段名中的特殊字符
|
297
|
+
escaped_field_name = re.escape(field_name_raw)
|
298
|
+
|
299
|
+
# 字段声明模式
|
300
|
+
patterns = [
|
301
|
+
# 标准字段声明: private Type fieldName_ = value;
|
302
|
+
rf'private\s+([^\s]+(?:<[^>]*>)?(?:\[\])?)\s+{escaped_field_name}\s*=',
|
303
|
+
# 简单字段声明: private Type fieldName_;
|
304
|
+
rf'private\s+([^\s]+(?:<[^>]*>)?(?:\[\])?)\s+{escaped_field_name}\s*;',
|
305
|
+
# 其他访问修饰符
|
306
|
+
rf'(?:public|protected|package)\s+([^\s]+(?:<[^>]*>)?(?:\[\])?)\s+{escaped_field_name}\s*[=;]',
|
307
|
+
# 无访问修饰符
|
308
|
+
rf'([^\s]+(?:<[^>]*>)?(?:\[\])?)\s+{escaped_field_name}\s*[=;]',
|
309
|
+
]
|
310
|
+
|
311
|
+
for pattern in patterns:
|
312
|
+
matches = re.finditer(pattern, content, re.MULTILINE)
|
313
|
+
for match in matches:
|
314
|
+
field_type = match.group(1).strip()
|
315
|
+
|
316
|
+
# 清理类型字符串
|
317
|
+
cleaned_type = self._clean_field_type(field_type)
|
318
|
+
if cleaned_type:
|
319
|
+
self.logger.debug(f"找到字段类型: {field_name_raw} -> {cleaned_type}")
|
320
|
+
return cleaned_type
|
321
|
+
|
322
|
+
self.logger.debug(f"未找到字段类型: {field_name_raw}")
|
323
|
+
return None
|
324
|
+
|
325
|
+
def _clean_field_type(self, field_type: str) -> Optional[str]:
|
326
|
+
"""
|
327
|
+
清理和标准化字段类型字符串
|
328
|
+
|
329
|
+
Args:
|
330
|
+
field_type: 原始字段类型字符串
|
331
|
+
|
332
|
+
Returns:
|
333
|
+
清理后的字段类型,如果无效则返回None
|
334
|
+
"""
|
335
|
+
if not field_type:
|
336
|
+
return None
|
337
|
+
|
338
|
+
# 移除多余的空白字符
|
339
|
+
field_type = field_type.strip()
|
340
|
+
|
341
|
+
# 跳过明显不是类型的字符串
|
342
|
+
if field_type in ['private', 'public', 'protected', 'static', 'final', 'volatile', 'transient']:
|
343
|
+
return None
|
344
|
+
|
345
|
+
# 处理泛型类型,保留完整的泛型信息
|
346
|
+
# 例如: MapFieldLite<String, Contact> 保持不变
|
347
|
+
|
348
|
+
# 处理数组类型
|
349
|
+
# 例如: String[] 保持不变
|
350
|
+
|
351
|
+
# 处理完全限定类名,提取简单类名
|
352
|
+
if '.' in field_type and not field_type.startswith('java.'):
|
353
|
+
# 对于非java包的类,保留完整路径以便后续处理
|
354
|
+
pass
|
355
|
+
|
356
|
+
return field_type
|
reproto-0.0.4/.git/index
DELETED
Binary file
|
reproto-0.0.4/.git/logs/HEAD
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
0000000000000000000000000000000000000000 514d3a743bced9f5c012a21032b49b81daec78ff iyue <ys1231@126.com> 1750903749 +0800 clone: from github.com:ys1231/reproto.git
|
@@ -1 +0,0 @@
|
|
1
|
-
0000000000000000000000000000000000000000 514d3a743bced9f5c012a21032b49b81daec78ff iyue <ys1231@126.com> 1750903749 +0800 clone: from github.com:ys1231/reproto.git
|
@@ -1 +0,0 @@
|
|
1
|
-
0000000000000000000000000000000000000000 514d3a743bced9f5c012a21032b49b81daec78ff iyue <ys1231@126.com> 1750903749 +0800 clone: from github.com:ys1231/reproto.git
|
Binary file
|
Binary file
|
reproto-0.0.4/.git/packed-refs
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
514d3a743bced9f5c012a21032b49b81daec78ff
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|
File without changes
|