Skip to content

Commit c287d1a

Browse files
authored
Remove Jackson usage as intermediary (#892)
1 parent f48eacd commit c287d1a

File tree

16 files changed

+515
-404
lines changed

16 files changed

+515
-404
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,6 @@ src/main/webapp/js/bundles
2222
.factorypath
2323

2424
*.dylib
25+
26+
# macOS
27+
.DS_Store

src/main/java/io/jenkins/plugins/pipelinegraphview/consoleview/PipelineConsoleViewAction.java

Lines changed: 21 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package io.jenkins.plugins.pipelinegraphview.consoleview;
22

3-
import com.fasterxml.jackson.core.JsonProcessingException;
4-
import com.fasterxml.jackson.databind.ObjectMapper;
53
import edu.umd.cs.findbugs.annotations.CheckForNull;
64
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
75
import hudson.Plugin;
@@ -37,6 +35,7 @@
3735
import java.util.List;
3836
import jenkins.model.Jenkins;
3937
import net.sf.json.JSONObject;
38+
import net.sf.json.JsonConfig;
4039
import org.jenkins.ui.icon.IconSpec;
4140
import org.jenkinsci.plugins.pipeline.modeldefinition.actions.RestartDeclarativePipelineAction;
4241
import org.jenkinsci.plugins.workflow.cps.replay.ReplayAction;
@@ -58,7 +57,12 @@ public class PipelineConsoleViewAction implements Action, IconSpec {
5857
public static final String URL_NAME = "pipeline-overview";
5958

6059
private static final Logger logger = LoggerFactory.getLogger(PipelineConsoleViewAction.class);
61-
private static final ObjectMapper MAPPER = new ObjectMapper();
60+
private static final JsonConfig jsonConfig = new JsonConfig();
61+
62+
static {
63+
PipelineStepList.PipelineStepListJsonProcessor.configure(jsonConfig);
64+
PipelineGraph.PipelineGraphJsonProcessor.configure(jsonConfig);
65+
}
6266

6367
private final PipelineGraphApi graphApi;
6468
private final WorkflowRun run;
@@ -84,7 +88,7 @@ public String getUrlName() {
8488
// running).
8589
@GET
8690
@WebMethod(name = "steps")
87-
public HttpResponse getSteps(StaplerRequest2 req) throws IOException {
91+
public HttpResponse getSteps(StaplerRequest2 req) {
8892
String nodeId = req.getParameter("nodeId");
8993
if (nodeId != null) {
9094
return HttpResponses.okJSON(getSteps(nodeId));
@@ -93,32 +97,28 @@ public HttpResponse getSteps(StaplerRequest2 req) throws IOException {
9397
}
9498
}
9599

96-
private JSONObject getSteps(String nodeId) throws IOException {
100+
private JSONObject getSteps(String nodeId) {
97101
logger.debug("getSteps was passed nodeId '{}'.", nodeId);
98102
PipelineStepList steps = stepApi.getSteps(nodeId);
99-
String stepsJson = MAPPER.writeValueAsString(steps);
100-
if (logger.isDebugEnabled()) {
101-
logger.debug("Steps for {}: '{}'.", nodeId, stepsJson);
102-
}
103-
return JSONObject.fromObject(stepsJson);
103+
JSONObject json = JSONObject.fromObject(steps, jsonConfig);
104+
logger.debug("Steps for {}: '{}'.", nodeId, json);
105+
return json;
104106
}
105107

106108
// Return all steps to:
107109
// - reduce number of API calls
108110
// - remove dependency of getting list of stages in frontend.
109111
@GET
110112
@WebMethod(name = "allSteps")
111-
public HttpResponse getAllSteps(StaplerRequest2 req) throws IOException {
113+
public HttpResponse getAllSteps(StaplerRequest2 req) {
112114
return HttpResponses.okJSON(getAllSteps());
113115
}
114116

115-
private JSONObject getAllSteps() throws IOException {
117+
private JSONObject getAllSteps() {
116118
PipelineStepList steps = stepApi.getAllSteps();
117-
String stepsJson = MAPPER.writeValueAsString(steps);
118-
if (logger.isDebugEnabled()) {
119-
logger.debug("Steps: '{}'.", stepsJson);
120-
}
121-
return JSONObject.fromObject(stepsJson);
119+
JSONObject json = JSONObject.fromObject(steps, jsonConfig);
120+
logger.debug("Steps: '{}'.", json);
121+
return json;
122122
}
123123

124124
@WebMethod(name = "log")
@@ -148,8 +148,8 @@ public void getConsoleText(StaplerRequest2 req, StaplerResponse2 rsp) throws IOE
148148
// Potentially a stage, so get the log text for the stage.
149149
boolean foundLogs = false;
150150
PipelineStepList steps = stepApi.getSteps(nodeId);
151-
for (PipelineStep step : steps.getSteps()) {
152-
logText = getLogForNode(step.getId());
151+
for (PipelineStep step : steps.steps) {
152+
logText = getLogForNode(step.id);
153153
if (logText != null) {
154154
foundLogs = true;
155155
logText.writeLogTo(0L, rsp.getOutputStream());
@@ -471,14 +471,13 @@ public String getNextBuildNumber() {
471471

472472
@GET
473473
@WebMethod(name = "tree")
474-
public HttpResponse getTree() throws JsonProcessingException {
474+
public HttpResponse getTree() {
475475
if (run == null) {
476476
return HttpResponses.errorJSON("No run to get tree for");
477477
}
478478
run.checkPermission(Item.READ);
479479
PipelineGraph tree = graphApi.createTree();
480-
String graph = MAPPER.writeValueAsString(tree);
481-
return HttpResponses.okJSON(JSONObject.fromObject(graph));
480+
return HttpResponses.okJSON(JSONObject.fromObject(tree, jsonConfig));
482481
}
483482

484483
// Icon related methods these may appear as unused but are used by /lib/hudson/buildCaption.jelly

src/main/java/io/jenkins/plugins/pipelinegraphview/multipipelinegraphview/MultiPipelineGraphViewAction.java

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,14 @@
11
package io.jenkins.plugins.pipelinegraphview.multipipelinegraphview;
22

3-
import com.fasterxml.jackson.core.JsonProcessingException;
4-
import com.fasterxml.jackson.databind.ObjectMapper;
53
import hudson.model.Action;
64
import hudson.model.Item;
75
import hudson.security.Permission;
86
import hudson.util.HttpResponses;
97
import hudson.util.RunList;
108
import io.jenkins.plugins.pipelinegraphview.PipelineGraphViewConfiguration;
11-
import java.util.ArrayList;
129
import java.util.List;
1310
import net.sf.json.JSONArray;
11+
import net.sf.json.JsonConfig;
1412
import org.jenkins.ui.icon.IconSpec;
1513
import org.jenkinsci.plugins.workflow.job.WorkflowJob;
1614
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
@@ -19,7 +17,6 @@
1917
import org.kohsuke.stapler.verb.GET;
2018

2119
public class MultiPipelineGraphViewAction implements Action, IconSpec {
22-
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
2320
private static final int MaxNumberOfElements = 10;
2421

2522
private final WorkflowJob target;
@@ -59,24 +56,22 @@ public boolean isShowStageDurations() {
5956
return PipelineGraphViewConfiguration.get().isShowStageDurations();
6057
}
6158

59+
private static final JsonConfig jsonConfig = new JsonConfig();
60+
61+
static {
62+
PipelineRun.PipelineRunJsonProcessor.configure(jsonConfig);
63+
}
64+
6265
@GET
6366
@WebMethod(name = "runs")
64-
public HttpResponse getRuns() throws JsonProcessingException {
67+
public HttpResponse getRuns() {
6568
RunList<WorkflowRun> runs = target.getBuilds();
66-
List<PipelineRun> pipelineRuns = new ArrayList<>();
67-
for (WorkflowRun run : runs) {
68-
pipelineRuns.add(new PipelineRun(run));
69-
if (pipelineRuns.size() >= MaxNumberOfElements) break;
70-
}
71-
JSONArray graph = createJson(pipelineRuns);
69+
List<PipelineRun> pipelineRuns =
70+
runs.stream().limit(MaxNumberOfElements).map(PipelineRun::new).toList();
71+
JSONArray graph = JSONArray.fromObject(pipelineRuns, jsonConfig);
7272
return HttpResponses.okJSON(graph);
7373
}
7474

75-
protected JSONArray createJson(List<PipelineRun> pipelineRuns) throws JsonProcessingException {
76-
String graph = OBJECT_MAPPER.writeValueAsString(pipelineRuns);
77-
return JSONArray.fromObject(graph);
78-
}
79-
8075
public String getJobUrl() {
8176
return target.getUrl();
8277
}

src/main/java/io/jenkins/plugins/pipelinegraphview/multipipelinegraphview/PipelineRun.java

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
import static io.jenkins.plugins.pipelinegraphview.utils.ChangesUtil.getChanges;
44

55
import io.jenkins.plugins.pipelinegraphview.utils.PipelineState;
6+
import net.sf.json.JSONObject;
7+
import net.sf.json.JsonConfig;
8+
import net.sf.json.processors.JsonBeanProcessor;
69
import org.jenkinsci.plugins.workflow.job.WorkflowRun;
710

811
public class PipelineRun {
@@ -46,4 +49,27 @@ public int getChangesCount() {
4649
public PipelineState getResult() {
4750
return result;
4851
}
52+
53+
public static class PipelineRunJsonProcessor implements JsonBeanProcessor {
54+
55+
public static void configure(JsonConfig config) {
56+
config.registerJsonBeanProcessor(PipelineRun.class, new PipelineRunJsonProcessor());
57+
PipelineState.PipelineStateJsonProcessor.configure(config);
58+
}
59+
60+
@Override
61+
public JSONObject processBean(Object bean, JsonConfig jsonConfig) {
62+
if (!(bean instanceof PipelineRun run)) {
63+
return null;
64+
}
65+
JSONObject json = new JSONObject();
66+
json.element("id", run.getId());
67+
json.element("displayName", run.getDisplayName());
68+
json.element("timestamp", run.getTimestamp());
69+
json.element("duration", run.getDuration());
70+
json.element("changesCount", run.getChangesCount());
71+
json.element("result", run.getResult(), jsonConfig);
72+
return json;
73+
}
74+
}
4975
}
Lines changed: 29 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
11
package io.jenkins.plugins.pipelinegraphview.utils;
22

33
import io.jenkins.plugins.pipelinegraphview.analysis.TimingInfo;
4+
import net.sf.json.JSONObject;
5+
import net.sf.json.JsonConfig;
6+
import net.sf.json.processors.JsonBeanProcessor;
47

58
public class AbstractPipelineNode {
6-
private String name;
7-
private PipelineState state;
8-
private String type; // TODO enum
9-
private String title;
10-
private String id;
11-
private long pauseDurationMillis;
12-
private long totalDurationMillis;
13-
private TimingInfo timingInfo;
9+
final String name;
10+
final PipelineState state;
11+
final String type; // TODO enum
12+
final String title;
13+
public final String id;
14+
private final long pauseDurationMillis;
15+
private final long totalDurationMillis;
16+
final TimingInfo timingInfo;
1417

1518
public AbstractPipelineNode(
1619
String id, String name, PipelineState state, String type, String title, TimingInfo timingInfo) {
@@ -25,10 +28,6 @@ public AbstractPipelineNode(
2528
this.totalDurationMillis = timingInfo.getTotalDurationMillis();
2629
}
2730

28-
public long getPauseDurationMillis() {
29-
return pauseDurationMillis;
30-
}
31-
3231
public long getStartTimeMillis() {
3332
return timingInfo.getStartTimeMillis();
3433
}
@@ -37,27 +36,23 @@ public Long getTotalDurationMillis() {
3736
return state.isInProgress() ? null : totalDurationMillis;
3837
}
3938

40-
public String getId() {
41-
return id;
42-
}
43-
44-
public String getName() {
45-
return name;
46-
}
47-
48-
public PipelineState getState() {
49-
return state;
50-
}
51-
52-
public String getType() {
53-
return type;
54-
}
55-
56-
public String getTitle() {
57-
return title;
58-
}
59-
60-
protected TimingInfo getTimingInfo() {
61-
return this.timingInfo;
39+
abstract static class AbstractPipelineNodeJsonProcessor implements JsonBeanProcessor {
40+
41+
protected static void baseConfigure(JsonConfig config) {
42+
config.registerJsonValueProcessor(PipelineState.class, new PipelineState.PipelineStateJsonProcessor());
43+
}
44+
45+
protected JSONObject create(AbstractPipelineNode node, JsonConfig config) {
46+
JSONObject json = new JSONObject();
47+
json.element("id", node.id);
48+
json.element("name", node.name);
49+
json.element("state", node.state, config);
50+
json.element("type", node.type);
51+
json.element("title", node.title);
52+
json.element("pauseDurationMillis", node.pauseDurationMillis);
53+
json.element("startTimeMillis", node.getStartTimeMillis());
54+
json.element("totalDurationMillis", node.getTotalDurationMillis());
55+
return json;
56+
}
6257
}
6358
}
Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,35 @@
11
package io.jenkins.plugins.pipelinegraphview.utils;
22

33
import java.util.List;
4+
import net.sf.json.JSONObject;
5+
import net.sf.json.JsonConfig;
6+
import net.sf.json.processors.JsonBeanProcessor;
47

58
public class PipelineGraph {
69

7-
private List<PipelineStage> stages;
8-
private boolean complete = false;
10+
final List<PipelineStage> stages;
11+
private final boolean complete;
912

1013
public PipelineGraph(List<PipelineStage> stages, boolean complete) {
1114
this.stages = stages;
1215
this.complete = complete;
1316
}
1417

15-
public boolean isComplete() {
16-
return complete;
17-
}
18+
public static class PipelineGraphJsonProcessor implements JsonBeanProcessor {
19+
public static void configure(JsonConfig config) {
20+
config.registerJsonBeanProcessor(PipelineGraph.class, new PipelineGraphJsonProcessor());
21+
PipelineStage.PipelineStageJsonProcessor.configure(config);
22+
}
1823

19-
public List<PipelineStage> getStages() {
20-
return stages;
24+
@Override
25+
public JSONObject processBean(Object bean, JsonConfig jsonConfig) {
26+
if (!(bean instanceof PipelineGraph graph)) {
27+
return null;
28+
}
29+
JSONObject json = new JSONObject();
30+
json.element("complete", graph.complete);
31+
json.element("stages", graph.stages, jsonConfig);
32+
return json;
33+
}
2134
}
2235
}

src/main/java/io/jenkins/plugins/pipelinegraphview/utils/PipelineGraphApi.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ private PipelineGraph createTree(PipelineGraphBuilderApi builder) {
9393

9494
return pipelineStageInternal.toPipelineStage(children, runUrl);
9595
})
96-
.filter(stage -> !childNodes.contains(stage.getId()))
96+
.filter(stage -> !childNodes.contains(stage.id))
9797
.collect(Collectors.toList());
9898
return new PipelineGraph(stageResults, execution.isComplete());
9999
}
Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,27 @@
11
package io.jenkins.plugins.pipelinegraphview.utils;
22

3-
public record PipelineInputStep(String message, String cancel, String id, String ok, boolean parameters) {}
3+
import net.sf.json.JSONObject;
4+
import net.sf.json.JsonConfig;
5+
import net.sf.json.processors.JsonBeanProcessor;
6+
7+
public record PipelineInputStep(String message, String cancel, String id, String ok, boolean parameters) {
8+
public static class PipelineInputStepJsonProcessor implements JsonBeanProcessor {
9+
@Override
10+
public JSONObject processBean(Object bean, JsonConfig jsonConfig) {
11+
if (!(bean instanceof PipelineInputStep input)) {
12+
return null;
13+
}
14+
JSONObject json = new JSONObject();
15+
json.element("message", input.message());
16+
json.element("cancel", input.cancel());
17+
json.element("id", input.id());
18+
json.element("ok", input.ok());
19+
json.element("parameters", input.parameters());
20+
return json;
21+
}
22+
23+
public static void configure(JsonConfig config) {
24+
config.registerJsonBeanProcessor(PipelineInputStep.class, new PipelineInputStepJsonProcessor());
25+
}
26+
}
27+
}

0 commit comments

Comments
 (0)