Skip to content

Commit b2fb467

Browse files
authored
Merge pull request #22 from nddipiazza/issue_21_deserialize_x12
Issue 21 serialize back to x12
2 parents ec788b4 + 9d46214 commit b2fb467

File tree

9 files changed

+323
-52
lines changed

9 files changed

+323
-52
lines changed

build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ dependencies {
3030
api 'com.thoughtworks.xstream:xstream:1.4.11.1'
3131

3232
testImplementation 'junit:junit:4.13'
33+
testImplementation 'commons-io:commons-io:2.6'
3334
}
3435

3536
jar {
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.imsweb.x12;
2+
3+
/**
4+
* Choice of line break when serializing x12 documents.
5+
*/
6+
public enum LineBreak {
7+
8+
/**
9+
* Unix line endings.
10+
*/
11+
LF("\n"),
12+
/**
13+
* Windows line endings.
14+
*/
15+
CRLF("\r\n"),
16+
/**
17+
* No line breaks at all.
18+
*/
19+
NONE("");
20+
21+
private String _lineBreakString;
22+
23+
LineBreak(String lineBreakString) {
24+
this._lineBreakString = lineBreakString;
25+
}
26+
27+
public String getLineBreakString() {
28+
return _lineBreakString;
29+
}
30+
}

src/main/java/com/imsweb/x12/Loop.java

Lines changed: 74 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,14 @@
66
import java.util.Iterator;
77
import java.util.List;
88
import java.util.Objects;
9+
import java.util.Set;
10+
import java.util.TreeSet;
911
import java.util.stream.Collectors;
1012

13+
import com.imsweb.x12.converters.ElementConverter;
14+
import com.imsweb.x12.mapping.LoopDefinition;
15+
import com.imsweb.x12.mapping.Positioned;
16+
import com.imsweb.x12.mapping.SegmentDefinition;
1117
import com.thoughtworks.xstream.XStream;
1218
import com.thoughtworks.xstream.annotations.XStreamAlias;
1319
import com.thoughtworks.xstream.annotations.XStreamOmitField;
@@ -19,8 +25,6 @@
1925
import com.thoughtworks.xstream.security.NoTypePermission;
2026
import com.thoughtworks.xstream.security.WildcardTypePermission;
2127

22-
import com.imsweb.x12.converters.ElementConverter;
23-
2428
/**
2529
* The Loop class is the representation of an Loop in a ANSI X12 transaction. The building block of an X12 transaction is an element. Some
2630
* elements may be made of sub elements. Elements combine to form segments. Segments are grouped as loops. And a set of loops form an X12
@@ -567,7 +571,9 @@ public Loop findTopParentById(String parentId) {
567571
}
568572

569573
/**
570-
* Returns the Loop in X12 String format. This method is used to convert the X12 object into a X12 transaction.
574+
* Returns an X12 String for this loop, but it will not be
575+
* properly ordered. For properly ordered X12 string use toX12String.
576+
*
571577
* @return String representation
572578
*/
573579
@Override
@@ -584,6 +590,71 @@ public String toString() {
584590
return dump.toString();
585591
}
586592

593+
/**
594+
* Returns the Loop in X12 String format. This method is used to convert the X12 object into a X12 transaction.
595+
*
596+
* This will first go through each segment and will return the properly separated string for the segment.
597+
*
598+
* After the segments are seriaized to X12 strings, it will then go through the Loops (in the correct order) and
599+
* recursively call this function for the child loops.
600+
*
601+
* @param loopDefinition The definition of the loop that we are currently on.
602+
* @return String representation The segments from this loop, including child loops.
603+
*/
604+
public String toX12String(LoopDefinition loopDefinition) {
605+
StringBuilder dump = new StringBuilder();
606+
607+
Set<Positioned> segmentsAndLoops = new TreeSet<>();
608+
if (loopDefinition.getLoop() != null) {
609+
segmentsAndLoops.addAll(loopDefinition.getLoop());
610+
}
611+
if (loopDefinition.getSegment() != null) {
612+
segmentsAndLoops.addAll(loopDefinition.getSegment());
613+
}
614+
for (Positioned positioned : segmentsAndLoops) {
615+
if (positioned instanceof SegmentDefinition) {
616+
SegmentDefinition segmentDefinition = (SegmentDefinition)positioned;
617+
int idx = 0;
618+
Segment segment;
619+
while ((segment = getSegment(segmentDefinition.getXid(), idx++)) != null) {
620+
dump.append(segment);
621+
dump.append(_separators.getSegment());
622+
dump.append(_separators.getLineBreak().getLineBreakString());
623+
}
624+
}
625+
else if (positioned instanceof LoopDefinition) {
626+
LoopDefinition innerLoopDefinition = (LoopDefinition)positioned;
627+
int idx = 0;
628+
Loop innerLoop;
629+
while ((innerLoop = getLoopForPrinting(innerLoopDefinition, idx++)) != null) {
630+
dump.append(innerLoop.toX12String(innerLoopDefinition));
631+
}
632+
}
633+
}
634+
return dump.toString();
635+
}
636+
637+
/**
638+
* Send a LoopDefinition and the index of an loop, fetch the loop from the
639+
* child loops that matches, given that the parentLoop has this loop as a child.
640+
* @param loopDefinition Loop definition for this spot in the x12 document.
641+
* @param idx The index of the loops returned thus far.
642+
* @return The child loop from the loops, or null otherwise.
643+
*/
644+
private Loop getLoopForPrinting(LoopDefinition loopDefinition, int idx) {
645+
Loop loop = getLoop(loopDefinition.getXid(), idx);
646+
647+
// We need to check that the loop we have gotten from getLoop
648+
// is actually a direct child of the current loop we are processing from the
649+
// loop definition.
650+
651+
if (loop != null && _loops.stream().noneMatch(parentLoop -> parentLoop.getId().equals(loop.getId()))) {
652+
return null;
653+
}
654+
655+
return loop;
656+
}
657+
587658
/**
588659
* Returns the Loop in XML String format.
589660
* @return XML String

src/main/java/com/imsweb/x12/Separators.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class Separators {
1414
private Pattern _segmentPattern;
1515
private Pattern _elementPattern;
1616
private Pattern _compositePattern;
17+
private LineBreak _lineBreak;
1718

1819
/**
1920
* Default constructor.
@@ -22,6 +23,7 @@ public Separators() {
2223
setSegment('~');
2324
setElement('*');
2425
setCompositeElement(':');
26+
setLineBreak(LineBreak.NONE);
2527
}
2628

2729
/**
@@ -107,6 +109,14 @@ public String[] splitComposite(String line) {
107109
return (line != null && _compositePattern != null) ? _compositePattern.split(line) : null;
108110
}
109111

112+
public LineBreak getLineBreak() {
113+
return _lineBreak;
114+
}
115+
116+
public void setLineBreak(LineBreak lineBreak) {
117+
this._lineBreak = lineBreak;
118+
}
119+
110120
@Override
111121
public boolean equals(Object o) {
112122
if (this == o) return true;

src/main/java/com/imsweb/x12/mapping/LoopDefinition.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44
package com.imsweb.x12.mapping;
55

66
import java.util.List;
7+
import java.util.Objects;
78

9+
import com.imsweb.x12.mapping.TransactionDefinition.Usage;
810
import com.thoughtworks.xstream.annotations.XStreamAlias;
911
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
1012
import com.thoughtworks.xstream.annotations.XStreamConverter;
1113
import com.thoughtworks.xstream.annotations.XStreamImplicit;
1214

13-
import com.imsweb.x12.mapping.TransactionDefinition.Usage;
14-
1515
@XStreamAlias("loop")
16-
public class LoopDefinition {
16+
public class LoopDefinition implements Positioned {
1717

1818
@XStreamAlias("xid")
1919
@XStreamAsAttribute
@@ -37,6 +37,7 @@ public class LoopDefinition {
3737
@XStreamImplicit
3838
private List<LoopDefinition> _loop;
3939

40+
@Override
4041
public String getXid() {
4142
return _xid;
4243
}
@@ -49,6 +50,7 @@ public Usage getUsage() {
4950
return _usage;
5051
}
5152

53+
@Override
5254
public String getPos() {
5355
return _pos;
5456
}
@@ -69,4 +71,23 @@ public List<LoopDefinition> getLoop() {
6971
return _loop;
7072
}
7173

74+
@Override
75+
public boolean equals(Object o) {
76+
if (this == o) return true;
77+
if (o == null || getClass() != o.getClass()) return false;
78+
LoopDefinition that = (LoopDefinition) o;
79+
return Objects.equals(_xid, that._xid) &&
80+
Objects.equals(_type, that._type) &&
81+
_usage == that._usage &&
82+
Objects.equals(_pos, that._pos) &&
83+
Objects.equals(_repeat, that._repeat) &&
84+
Objects.equals(_name, that._name) &&
85+
Objects.equals(_segment, that._segment) &&
86+
Objects.equals(_loop, that._loop);
87+
}
88+
89+
@Override
90+
public int hashCode() {
91+
return Objects.hash(_xid, _type, _usage, _pos, _repeat, _name, _segment, _loop);
92+
}
7293
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package com.imsweb.x12.mapping;
2+
3+
import java.util.Objects;
4+
5+
public interface Positioned extends Comparable<Positioned> {
6+
String getXid();
7+
String getPos();
8+
9+
@Override
10+
default int compareTo(Positioned o) {
11+
Objects.requireNonNull(o);
12+
if (getPos().equals(o.getPos())) {
13+
return getXid().compareTo(o.getXid());
14+
}
15+
return getPos().compareTo(o.getPos());
16+
}
17+
}

src/main/java/com/imsweb/x12/mapping/SegmentDefinition.java

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,16 +4,16 @@
44
package com.imsweb.x12.mapping;
55

66
import java.util.List;
7+
import java.util.Objects;
78

9+
import com.imsweb.x12.mapping.TransactionDefinition.Usage;
810
import com.thoughtworks.xstream.annotations.XStreamAlias;
911
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
1012
import com.thoughtworks.xstream.annotations.XStreamConverter;
1113
import com.thoughtworks.xstream.annotations.XStreamImplicit;
1214

13-
import com.imsweb.x12.mapping.TransactionDefinition.Usage;
14-
1515
@XStreamAlias("segment")
16-
public class SegmentDefinition {
16+
public class SegmentDefinition implements Positioned {
1717

1818
@XStreamAlias("xid")
1919
@XStreamAsAttribute
@@ -37,6 +37,7 @@ public class SegmentDefinition {
3737
@XStreamImplicit
3838
private List<CompositeDefinition> _composites;
3939

40+
@Override
4041
public String getXid() {
4142
return _xid;
4243
}
@@ -49,6 +50,7 @@ public Usage getUsage() {
4950
return _usage;
5051
}
5152

53+
@Override
5254
public String getPos() {
5355
return _pos;
5456
}
@@ -69,4 +71,23 @@ public List<CompositeDefinition> getComposites() {
6971
return _composites;
7072
}
7173

74+
@Override
75+
public boolean equals(Object o) {
76+
if (this == o) return true;
77+
if (o == null || getClass() != o.getClass()) return false;
78+
SegmentDefinition that = (SegmentDefinition) o;
79+
return Objects.equals(_xid, that._xid) &&
80+
Objects.equals(_name, that._name) &&
81+
_usage == that._usage &&
82+
Objects.equals(_pos, that._pos) &&
83+
Objects.equals(_maxUse, that._maxUse) &&
84+
Objects.equals(_syntax, that._syntax) &&
85+
Objects.equals(_elements, that._elements) &&
86+
Objects.equals(_composites, that._composites);
87+
}
88+
89+
@Override
90+
public int hashCode() {
91+
return Objects.hash(_xid, _name, _usage, _pos, _maxUse, _syntax, _elements, _composites);
92+
}
7293
}

0 commit comments

Comments
 (0)