2 * Copyright (c) 2017 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.mdsal.binding.javav2.java.api.generator.util;
10 import java.util.ArrayList;
11 import java.util.List;
12 import javax.annotation.RegEx;
13 import org.apache.commons.lang3.StringUtils;
16 * Pretty-print utility for generated Java code.
18 public final class JavaCodePrettyPrint {
21 private static final String JDOC_START = "/**";
22 private static final String JDOC_PART = " *";
23 private static final String JDOC_END = "*/";
26 private static final String COMMENTS = "//";
29 private static final char START_BODY = '{';
30 private static final char END_BODY = '}';
34 private static final String NEW_LINE_REGEX = "\\r?\\n";
36 private static final String WS_REGEX = "\\s+";
37 private static final char SPACE = ' ';
38 private static final char NEW_LINE = '\n';
41 private static final int INDENT = 4;
44 private static final String PACKAGE = "package";
45 private static final String IMPORT = "import";
48 private static final char END_LINE = ';';
49 private static final char AT = '@';
51 private JavaCodePrettyPrint() {
52 throw new UnsupportedOperationException("Util class");
56 * Pretty-print generated Java code.
58 * @param unformedJavaFile
59 * - unformed Java file from generator
60 * @return formed Java file
62 public static String perform(final String unformedJavaFile) {
63 final StringBuilder sb = new StringBuilder();
64 String[] splittedByNewLine = unformedJavaFile.split(NEW_LINE_REGEX);
65 // remove excessive whitespaces
66 splittedByNewLine = phaseOne(splittedByNewLine);
67 // merge or divide lines which need it && setup base new lines at the
69 splittedByNewLine = phaseTwo(splittedByNewLine);
71 splittedByNewLine = phaseThree(splittedByNewLine);
73 for (final String line : splittedByNewLine) {
82 * @param splittedByNewLine
83 * - cleaned and merged/divided lines
84 * @return fixed intents in lines
86 private static String[] phaseThree(final String[] splittedByNewLine) {
88 final List<String> lines = new ArrayList<>();
89 for (int i = 0; i < splittedByNewLine.length; i++) {
90 final StringBuilder sb = new StringBuilder();
91 indentCount = lineIndent(sb, indentCount, splittedByNewLine[i]);
92 sb.append(splittedByNewLine[i]);
93 if ((splittedByNewLine[i].contains(String.valueOf(END_BODY))
94 || splittedByNewLine[i].contains(String.valueOf(END_LINE))) && indentCount == 1) {
97 lines.add(sb.toString());
100 return lines.toArray(new String[lines.size()]);
103 private static int lineIndent(final StringBuilder sb, final int indentCount, final String line) {
104 int newIndentCount = indentCount;
105 if (line.contains(String.valueOf(END_BODY)) && !line.startsWith(JDOC_PART)) {
108 for (int i = 0; i < (newIndentCount * INDENT); i++) {
112 if (line.contains(String.valueOf(START_BODY)) && !line.startsWith(JDOC_PART)) {
116 return newIndentCount;
120 * Join or split lines if necessary.
122 * @param splittedByNewLine
123 * - cleaned lines from whitespaces around them
124 * @return fixed lines
126 private static String[] phaseTwo(final String[] splittedByNewLine) {
127 final List<String> fixedLines = new ArrayList<>();
129 // prepare package part
130 if (splittedByNewLine[0].startsWith(PACKAGE)) {
131 fixedLines.add(new StringBuilder(splittedByNewLine[0]).append(NEW_LINE).append(NEW_LINE).toString());
136 if (splittedByNewLine[1].startsWith(IMPORT)) {
138 for (int i = 1; i < splittedByNewLine.length - 1; i++) {
139 if (!splittedByNewLine[i + 1].startsWith(IMPORT)) {
140 fixedLines.add(new StringBuilder(
141 splittedByNewLine[i]).append(NEW_LINE).append(NEW_LINE).toString());
145 fixedLines.add(new StringBuilder(splittedByNewLine[i]).append(NEW_LINE).toString());
153 StringBuilder sbLineClass = new StringBuilder();
154 int classStartEnd = 0;
155 for (int i = importsEndAt + 1; i < splittedByNewLine.length; i++) {
156 i = appendJDoc(splittedByNewLine, fixedLines, i);
157 if (!splittedByNewLine[i].contains(String.valueOf(START_BODY))) {
158 sbLineClass.append(splittedByNewLine[i]).append(SPACE);
160 fixedLines.add(sbLineClass.append(splittedByNewLine[i]).append(NEW_LINE).append(NEW_LINE).toString());
161 classStartEnd = i + 1;
166 for (int i = classStartEnd; i < splittedByNewLine.length; i++) {
167 i = appendJDoc(splittedByNewLine, fixedLines, i);
168 if (!splittedByNewLine[i].startsWith(COMMENTS)
169 && !splittedByNewLine[i].endsWith(String.valueOf(END_LINE))
170 && !splittedByNewLine[i].endsWith(String.valueOf(START_BODY))
171 && !splittedByNewLine[i].endsWith(String.valueOf(END_BODY))
172 && !splittedByNewLine[i].startsWith(String.valueOf(AT))) {
173 sbLineClass = new StringBuilder();
174 for (int j = i; j < splittedByNewLine.length; j++) {
175 if (!splittedByNewLine[j].contains(String.valueOf(START_BODY))
176 && !splittedByNewLine[j].contains(String.valueOf(END_LINE))) {
177 final String str = splittedByNewLine[j];
178 sbLineClass.append(str).append(SPACE);
180 fixedLines.add(sbLineClass.append(splittedByNewLine[j]).append(NEW_LINE).toString());
187 final String splStri = splittedByNewLine[i];
188 final String stringSB = String.valueOf(START_BODY);
189 final String stringEB = String.valueOf(END_BODY);
190 if (splStri.contains(stringSB) && splStri.endsWith(stringEB)) {
191 final StringBuilder sb = new StringBuilder();
192 for (int j = 0; j < splittedByNewLine[i].length(); j++) {
193 if (splittedByNewLine[i].charAt(j) == END_BODY) {
196 sb.append(splittedByNewLine[i].charAt(j));
197 if (splittedByNewLine[i].charAt(j) == START_BODY) {
201 final String[] split = sb.toString().split(NEW_LINE_REGEX);
202 for (final String s : split) {
203 fixedLines.add(new StringBuilder(s).append(NEW_LINE).toString());
207 fixedLines.add(new StringBuilder(splittedByNewLine[i]).append(NEW_LINE).toString());
210 return fixedLines.toArray(new String[fixedLines.size()]);
213 private static int appendJDoc(final String[] splittedByNewLine, final List<String> fixedLines, int cur) {
214 if (splittedByNewLine[cur].contains(JDOC_START)) {
215 fixedLines.add(new StringBuilder(splittedByNewLine[cur]).append(NEW_LINE).toString());
216 for (int next = cur + 1; next < splittedByNewLine.length - 1; next++) {
218 new StringBuilder().append(SPACE).append(splittedByNewLine[next]).append(NEW_LINE).toString());
219 if (splittedByNewLine[next].contains(JDOC_END)) {
229 * Remove empty lines and whitespaces adjacent lines.
231 * @param splittedByNewLine
232 * - lines with whitespaces around them
233 * @return cleaned lines from whitespaces
235 private static String[] phaseOne(final String[] splittedByNewLine) {
236 final List<String> linesWithoutWhitespaces = new ArrayList<>();
237 for (final String line : splittedByNewLine) {
238 if (!StringUtils.isBlank(line)) {
240 for (int i = 0; i < line.length(); i++) {
241 if (StringUtils.isWhitespace(String.valueOf(line.charAt(i)))) {
247 int lineEnd = line.length() - 1;
248 while (StringUtils.isWhitespace(String.valueOf(line.charAt(lineEnd)))) {
251 linesWithoutWhitespaces.add(line.substring(lineStart, lineEnd + 1));
254 return linesWithoutWhitespaces.toArray(new String[linesWithoutWhitespaces.size()]);