Skip to content

Commit 1834a65

Browse files
committed
Added a new lambda to split long fragments into compilable strings
1 parent 886995b commit 1834a65

File tree

2 files changed

+210
-0
lines changed

2 files changed

+210
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
/*
2+
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
3+
* Copyright 2018 SmartBear Software
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.openapitools.codegen.templating.mustache;
19+
20+
import java.io.IOException;
21+
import java.io.Writer;
22+
import java.util.Locale;
23+
24+
import com.samskivert.mustache.Mustache;
25+
import com.samskivert.mustache.Template.Fragment;
26+
27+
/**
28+
* Splits long fragments into smaller strings and uses a StringBuilder to merge
29+
* them back.
30+
*
31+
* Register:
32+
*
33+
* <pre>
34+
* additionalProperties.put("lambdaSplitString", new SplitStringLambda());
35+
* </pre>
36+
*
37+
* Use:
38+
*
39+
* <pre>
40+
* {{#lambdaSplitString}}{{summary}}{{/lambdaSplitString}}
41+
* </pre>
42+
*/
43+
public class SplitStringLambda implements Mustache.Lambda {
44+
private static final int DEFAULT_MAX_LENGTH = 65535;
45+
46+
private static final String SPLIT_INIT = "new StringBuilder(%d)";
47+
48+
private static final String SPLIT_PART = ".append(\"%s\")";
49+
50+
private static final String SPLIT_SUFFIX = ".toString()";
51+
52+
private final int maxLength;
53+
54+
public SplitStringLambda() {
55+
this(DEFAULT_MAX_LENGTH);
56+
}
57+
58+
public SplitStringLambda(int maxLength) {
59+
this.maxLength = maxLength;
60+
}
61+
62+
@Override
63+
public void execute(Fragment fragment, Writer writer) throws IOException {
64+
String input = fragment.execute();
65+
int inputLength = input.length();
66+
67+
StringBuilder builder = new StringBuilder();
68+
if (inputLength > maxLength) {
69+
70+
// Initialize a StringBuilder
71+
builder.append(String.format(Locale.ROOT, SPLIT_INIT, inputLength));
72+
73+
int currentPosition = 0;
74+
int currentStringLength = 0;
75+
char currentLastChar = '\\';
76+
77+
// Split input into parts of at most maxLength and not ending with an escape character
78+
// Append each part to the StringBuilder
79+
while (currentPosition + maxLength < input.length()) {
80+
currentStringLength = maxLength;
81+
currentLastChar = input.charAt(currentPosition + currentStringLength - 1);
82+
if (currentLastChar == '\\') {
83+
--currentStringLength;
84+
}
85+
86+
builder.append(String.format(Locale.ROOT, SPLIT_PART, input.substring(currentPosition, currentPosition + currentStringLength)));
87+
currentPosition += currentStringLength;
88+
}
89+
90+
// Append last part if necessary
91+
if (currentPosition < input.length()) {
92+
builder.append(String.format(Locale.ROOT, SPLIT_PART, input.substring(currentPosition)));
93+
}
94+
95+
// Close the builder and merge everything back to a string
96+
builder.append(SPLIT_SUFFIX);
97+
} else {
98+
builder.append(String.format(Locale.ROOT, "\"%s\"", input));
99+
}
100+
101+
writer.write(builder.toString());
102+
}
103+
104+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
/*
2+
* Copyright 2018 OpenAPI-Generator Contributors (https://openapi-generator.tech)
3+
* Copyright 2018 SmartBear Software
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*/
17+
18+
package org.openapitools.codegen.templating.mustache;
19+
20+
import static org.mockito.Mockito.when;
21+
import static org.testng.Assert.assertEquals;
22+
23+
import java.io.IOException;
24+
import java.io.StringWriter;
25+
import java.util.HashMap;
26+
import java.util.Locale;
27+
import java.util.Map;
28+
29+
import org.mockito.Mock;
30+
import org.mockito.Mockito;
31+
import org.mockito.MockitoAnnotations;
32+
import org.testng.annotations.AfterMethod;
33+
import org.testng.annotations.BeforeMethod;
34+
import org.testng.annotations.Test;
35+
36+
import com.samskivert.mustache.Template.Fragment;
37+
38+
public class SplitStringLambdaTest {
39+
private static final String INPUT_STRING = "1112223334";
40+
41+
private static final Map<Integer, String> EXPECTED_OUTPUTS;
42+
static {
43+
EXPECTED_OUTPUTS = new HashMap<>();
44+
EXPECTED_OUTPUTS.put(2,
45+
String.format(
46+
Locale.ROOT,
47+
"new StringBuilder(%d).append(\"11\").append(\"12\").append(\"22\").append(\"33\").append(\"34\").toString()",
48+
INPUT_STRING.length()));
49+
EXPECTED_OUTPUTS.put(3,
50+
String.format(
51+
Locale.ROOT,
52+
"new StringBuilder(%d).append(\"111\").append(\"222\").append(\"333\").append(\"4\").toString()",
53+
INPUT_STRING.length()));
54+
}
55+
56+
private static final String INPUT_QUOTED_STRING = "1\\\"11\\\"2223\\\"334";
57+
private static final String INPUT_QUOTED_OUTPUT = String.format(
58+
Locale.ROOT,
59+
"new StringBuilder(%d).append(\"1\\\"\").append(\"11\").append(\"\\\"2\").append(\"223\").append(\"\\\"3\").append(\"34\").toString()",
60+
INPUT_QUOTED_STRING.length());
61+
62+
@Mock
63+
private Fragment fragment;
64+
65+
@BeforeMethod
66+
public void init() {
67+
MockitoAnnotations.initMocks(this);
68+
}
69+
70+
@AfterMethod
71+
public void reset() {
72+
Mockito.reset(fragment);
73+
}
74+
75+
private void testString(String input, int maxLength, String expected) throws IOException {
76+
when(fragment.execute()).thenReturn(input);
77+
78+
StringWriter output = new StringWriter();
79+
new SplitStringLambda(maxLength).execute(fragment, output);
80+
assertEquals(output.toString(), expected);
81+
}
82+
83+
@Test
84+
public void testSplitGroupsOf2() throws IOException {
85+
int maxLength = 2;
86+
testString(INPUT_STRING, maxLength, EXPECTED_OUTPUTS.get(maxLength));
87+
}
88+
89+
@Test
90+
public void testSplitGroupsOf3() throws IOException {
91+
int maxLength = 3;
92+
testString(INPUT_STRING, maxLength, EXPECTED_OUTPUTS.get(maxLength));
93+
}
94+
95+
@Test
96+
public void testSplitQuotedString() throws IOException {
97+
int maxLength = 3;
98+
testString(INPUT_QUOTED_STRING, maxLength, INPUT_QUOTED_OUTPUT);
99+
}
100+
101+
@Test
102+
public void testShortString() throws IOException {
103+
testString(INPUT_STRING, INPUT_STRING.length(), String.format(Locale.ROOT, "\"%s\"", INPUT_STRING));
104+
}
105+
106+
}

0 commit comments

Comments
 (0)