in core/src/main/java/com/alibaba/fastjson2/JSONPath.java [520:852]
public static JSONPath of(
String[] paths,
Type[] types,
String[] formats,
long[] pathFeatures,
ZoneId zoneId,
JSONReader.Feature... features
) {
if (paths.length == 0) {
throw new JSONException("illegal paths, not support 0 length");
}
if (types == null) {
types = new Type[paths.length];
Arrays.fill(types, Object.class);
}
if (types.length != paths.length) {
throw new JSONException("types.length not equals paths.length");
}
JSONPath[] jsonPaths = new JSONPath[paths.length];
for (int i = 0; i < paths.length; i++) {
jsonPaths[i] = of(paths[i]);
}
boolean allSingleName = true, allSinglePositiveIndex = true;
boolean allTwoName = true, allTwoIndexPositive = true;
boolean allThreeName = true;
boolean sameMultiLength = true;
JSONPathMulti firstMulti = null;
for (int i = 0; i < jsonPaths.length; i++) {
JSONPath path = jsonPaths[i];
if (i == 0) {
if (path instanceof JSONPathMulti) {
firstMulti = (JSONPathMulti) path;
} else {
sameMultiLength = false;
}
} else {
if (sameMultiLength) {
if (path instanceof JSONPathMulti) {
if (((JSONPathMulti) path).segments.size() != firstMulti.segments.size()) {
sameMultiLength = false;
}
}
}
}
if (allSingleName && !(path instanceof JSONPathSingleName)) {
allSingleName = false;
}
if (allSinglePositiveIndex) {
if (!(path instanceof JSONPathSingleIndex)
|| ((JSONPathSingleIndex) path).index < 0) {
allSinglePositiveIndex = false;
}
}
if (allTwoName) {
if (path instanceof JSONPathTwoSegment) {
JSONPathTwoSegment two = (JSONPathTwoSegment) path;
if (!(two.second instanceof JSONPathSegmentName)) {
allTwoName = false;
}
} else {
allTwoName = false;
}
}
if (allTwoIndexPositive) {
if (path instanceof JSONPathTwoSegment) {
JSONPathTwoSegment two = (JSONPathTwoSegment) path;
if (!(two.second instanceof JSONPathSegmentIndex) || ((JSONPathSegmentIndex) two.second).index < 0) {
allTwoIndexPositive = false;
}
} else {
allTwoIndexPositive = false;
}
}
if (allThreeName) {
if (path instanceof JSONPathMulti) {
JSONPathMulti multi = (JSONPathMulti) path;
if (multi.segments.size() == 3) {
JSONPathSegment three = multi.segments.get(2);
if (multi.segments.get(0) instanceof JSONPathSegment.AllSegment
|| multi.segments.get(1) instanceof JSONPathSegment.AllSegment
|| !(three instanceof JSONPathSegmentName)) {
allThreeName = false;
}
} else {
allThreeName = false;
}
} else {
allThreeName = false;
}
}
}
long featuresValue = JSONReader.Feature.of(features);
if (allSingleName) {
return new JSONPathTypedMultiNames(
jsonPaths,
null,
jsonPaths,
types,
formats,
pathFeatures,
zoneId,
featuresValue
);
}
if (allSinglePositiveIndex) {
return new JSONPathTypedMultiIndexes(jsonPaths, null, jsonPaths, types, formats, pathFeatures, zoneId, featuresValue);
}
if (allTwoName || allTwoIndexPositive) {
boolean samePrefix = true;
JSONPathSegment first0 = ((JSONPathTwoSegment) jsonPaths[0]).first;
for (int i = 1; i < jsonPaths.length; i++) {
JSONPathTwoSegment two = (JSONPathTwoSegment) jsonPaths[i];
if (!first0.equals(two.first)) {
samePrefix = false;
break;
}
}
if (samePrefix) {
JSONPath firstPath = jsonPaths[0];
if (allTwoName) {
JSONPathSingleName[] names = new JSONPathSingleName[jsonPaths.length];
for (int i = 0; i < jsonPaths.length; i++) {
JSONPathTwoSegment two = (JSONPathTwoSegment) jsonPaths[i];
JSONPathSegmentName name = (JSONPathSegmentName) two.second;
names[i] = new JSONPathSingleName("$." + name, name);
}
String prefixPath = firstPath.path.substring(0, firstPath.path.length() - names[0].name.length() - 1);
if (first0 instanceof JSONPathSegmentName) {
JSONPathSegmentName name = (JSONPathSegmentName) first0;
JSONPath prefix = new JSONPathSingleName(prefixPath, name);
return new JSONPathTypedMultiNamesPrefixName1(
jsonPaths,
prefix,
names,
types,
formats,
pathFeatures,
zoneId,
featuresValue
);
} else if (first0 instanceof JSONPathSegmentIndex) {
JSONPathSegmentIndex first0Index = ((JSONPathSegmentIndex) first0);
if (first0Index.index >= 0) {
JSONPathSingleIndex prefix = new JSONPathSingleIndex(prefixPath, first0Index);
return new JSONPathTypedMultiNamesPrefixIndex1(
jsonPaths,
prefix,
names,
types,
formats,
pathFeatures,
zoneId,
featuresValue
);
}
}
} else {
JSONPathSingleIndex[] indexes = new JSONPathSingleIndex[jsonPaths.length];
for (int i = 0; i < jsonPaths.length; i++) {
JSONPathTwoSegment two = (JSONPathTwoSegment) jsonPaths[i];
JSONPathSegmentIndex name = (JSONPathSegmentIndex) two.second;
indexes[i] = new JSONPathSingleIndex("$" + name, name);
}
JSONPath prefix = null;
if (first0 instanceof JSONPathSegmentName) {
JSONPathSegmentName name = (JSONPathSegmentName) first0;
prefix = new JSONPathSingleName("$." + name.name, name);
} else if (first0 instanceof JSONPathSegmentIndex) {
JSONPathSegmentIndex index = (JSONPathSegmentIndex) first0;
prefix = new JSONPathSingleIndex("$[" + index.index + "]", index);
}
if (prefix != null) {
return new JSONPathTypedMultiIndexes(
jsonPaths,
prefix,
indexes,
types,
formats,
pathFeatures,
zoneId,
featuresValue
);
}
}
}
} else if (allThreeName) {
boolean samePrefix = true;
JSONPathSegment first0 = ((JSONPathMulti) jsonPaths[0]).segments.get(0);
JSONPathSegment first1 = ((JSONPathMulti) jsonPaths[0]).segments.get(1);
for (int i = 1; i < jsonPaths.length; i++) {
JSONPathMulti multi = (JSONPathMulti) jsonPaths[i];
if (!first0.equals(multi.segments.get(0))) {
samePrefix = false;
break;
}
if (!first1.equals(multi.segments.get(1))) {
samePrefix = false;
break;
}
}
if (samePrefix) {
JSONPathSingleName[] names = new JSONPathSingleName[jsonPaths.length];
for (int i = 0; i < jsonPaths.length; i++) {
JSONPathMulti multi = (JSONPathMulti) jsonPaths[i];
JSONPathSegmentName name = (JSONPathSegmentName) multi.segments.get(2);
names[i] = new JSONPathSingleName("$." + name, name);
}
JSONPath firstPath = jsonPaths[0];
String prefixPath = firstPath.path.substring(0, firstPath.path.length() - names[0].name.length() - 1);
JSONPathTwoSegment prefix = new JSONPathTwoSegment(prefixPath, first0, first1);
if (first0 instanceof JSONPathSegmentName && first1 instanceof JSONPathSegmentName) {
return new JSONPathTypedMultiNamesPrefixName2(
jsonPaths,
prefix,
names,
types,
formats,
pathFeatures,
zoneId,
featuresValue
);
}
return new JSONPathTypedMultiNames(
jsonPaths,
prefix,
names,
types,
formats,
pathFeatures,
zoneId,
featuresValue
);
}
}
if (sameMultiLength && paths.length > 1) {
boolean samePrefix = true;
boolean sameType = true;
int lastIndex = firstMulti.segments.size() - 1;
JSONPathSegment lastSegment = firstMulti.segments.get(lastIndex);
for (int i = 0; i < lastIndex; i++) {
JSONPathSegment segment = firstMulti.segments.get(i);
for (int j = 1; j < paths.length; j++) {
JSONPath jsonPath = jsonPaths[j];
JSONPathSegment segment1;
if (jsonPath instanceof JSONPathMulti) {
JSONPathMulti path = (JSONPathMulti) jsonPath;
segment1 = path.segments.get(i);
} else if (jsonPath instanceof JSONPathSingleName) {
segment1 = ((JSONPathSingleName) jsonPath).segment;
} else if (jsonPath instanceof JSONPathSingleIndex) {
segment1 = ((JSONPathSingleIndex) jsonPath).segment;
} else {
segment1 = null;
}
if (!segment.equals(segment1)) {
samePrefix = false;
break;
}
}
if (!samePrefix) {
break;
}
}
if (samePrefix) {
for (int i = 1; i < paths.length; i++) {
JSONPathMulti path = (JSONPathMulti) jsonPaths[i];
if (!lastSegment.getClass().equals(path.segments.get(lastIndex).getClass())) {
sameType = false;
break;
}
}
if (sameType) {
List<JSONPathSegment> prefixSegments = firstMulti.segments.subList(0, lastIndex - 1);
String prefixPath = null;
int dotIndex = firstMulti.path.lastIndexOf('.');
if (dotIndex != -1) {
prefixPath = firstMulti.path.substring(0, dotIndex - 1);
}
if (prefixPath != null) {
JSONPathMulti prefix = new JSONPathMulti(prefixPath, prefixSegments);
if (lastSegment instanceof JSONPathSegmentIndex) {
JSONPath[] indexPaths = new JSONPath[paths.length];
for (int i = 0; i < jsonPaths.length; i++) {
JSONPathMulti path = (JSONPathMulti) jsonPaths[i];
JSONPathSegmentIndex lastSegmentIndex = (JSONPathSegmentIndex) path.segments.get(lastIndex);
indexPaths[i] = new JSONPathSingleIndex(lastSegmentIndex.toString(), lastSegmentIndex);
}
return new JSONPathTypedMultiIndexes(
jsonPaths,
prefix,
indexPaths,
types,
formats,
pathFeatures,
zoneId,
featuresValue
);
}
}
}
}
}
return new JSONPathTypedMulti(jsonPaths, types, formats, pathFeatures, zoneId, featuresValue);
}