Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 21 serialize back to x12 #22

Merged
merged 14 commits into from
Mar 6, 2020
1 change: 1 addition & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ dependencies {
api 'com.thoughtworks.xstream:xstream:1.4.11.1'

testImplementation 'junit:junit:4.13'
testImplementation 'commons-io:commons-io:2.6'
}

jar {
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/com/imsweb/x12/LineBreak.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.imsweb.x12;

/**
* Choice of line break when serializing x12 documents.
*/
public enum LineBreak {

/**
* Unix line endings.
*/
LF("\n"),
/**
* Windows line endings.
*/
CRLF("\r\n"),
/**
* No line breaks at all.
*/
NONE("");

private String _lineBreakString;

LineBreak(String lineBreakString) {
this._lineBreakString = lineBreakString;
}

public String getLineBreakString() {
return _lineBreakString;
}
}
77 changes: 74 additions & 3 deletions src/main/java/com/imsweb/x12/Loop.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,14 @@
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;

import com.imsweb.x12.converters.ElementConverter;
import com.imsweb.x12.mapping.LoopDefinition;
import com.imsweb.x12.mapping.Positioned;
import com.imsweb.x12.mapping.SegmentDefinition;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamOmitField;
Expand All @@ -19,8 +25,6 @@
import com.thoughtworks.xstream.security.NoTypePermission;
import com.thoughtworks.xstream.security.WildcardTypePermission;

import com.imsweb.x12.converters.ElementConverter;

/**
* 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
* 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
Expand Down Expand Up @@ -567,7 +571,9 @@ public Loop findTopParentById(String parentId) {
}

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

/**
* Returns the Loop in X12 String format. This method is used to convert the X12 object into a X12 transaction.
*
* This will first go through each segment and will return the properly separated string for the segment.
*
* After the segments are seriaized to X12 strings, it will then go through the Loops (in the correct order) and
* recursively call this function for the child loops.
*
* @param loopDefinition The definition of the loop that we are currently on.
* @return String representation The segments from this loop, including child loops.
*/
public String toX12String(LoopDefinition loopDefinition) {
StringBuilder dump = new StringBuilder();

Set<Positioned> segmentsAndLoops = new TreeSet<>();
if (loopDefinition.getLoop() != null) {
segmentsAndLoops.addAll(loopDefinition.getLoop());
}
if (loopDefinition.getSegment() != null) {
segmentsAndLoops.addAll(loopDefinition.getSegment());
}
for (Positioned positioned : segmentsAndLoops) {
if (positioned instanceof SegmentDefinition) {
SegmentDefinition segmentDefinition = (SegmentDefinition)positioned;
int idx = 0;
Segment segment;
while ((segment = getSegment(segmentDefinition.getXid(), idx++)) != null) {
dump.append(segment);
dump.append(_separators.getSegment());
dump.append(_separators.getLineBreak().getLineBreakString());
}
}
else if (positioned instanceof LoopDefinition) {
LoopDefinition innerLoopDefinition = (LoopDefinition)positioned;
int idx = 0;
Loop innerLoop;
while ((innerLoop = getLoopForPrinting(innerLoopDefinition, idx++)) != null) {
dump.append(innerLoop.toX12String(innerLoopDefinition));
}
}
}
return dump.toString();
}

/**
* Send a LoopDefinition and the index of an loop, fetch the loop from the
* child loops that matches, given that the parentLoop has this loop as a child.
* @param loopDefinition Loop definition for this spot in the x12 document.
* @param idx The index of the loops returned thus far.
* @return The child loop from the loops, or null otherwise.
*/
private Loop getLoopForPrinting(LoopDefinition loopDefinition, int idx) {
Loop loop = getLoop(loopDefinition.getXid(), idx);

// We need to check that the loop we have gotten from getLoop
// is actually a direct child of the current loop we are processing from the
// loop definition.

if (loop != null && _loops.stream().noneMatch(parentLoop -> parentLoop.getId().equals(loop.getId()))) {
return null;
}

return loop;
}

/**
* Returns the Loop in XML String format.
* @return XML String
Expand Down
10 changes: 10 additions & 0 deletions src/main/java/com/imsweb/x12/Separators.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ public class Separators {
private Pattern _segmentPattern;
private Pattern _elementPattern;
private Pattern _compositePattern;
private LineBreak _lineBreak;

/**
* Default constructor.
Expand All @@ -22,6 +23,7 @@ public Separators() {
setSegment('~');
setElement('*');
setCompositeElement(':');
setLineBreak(LineBreak.NONE);
}

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

public LineBreak getLineBreak() {
return _lineBreak;
}

public void setLineBreak(LineBreak lineBreak) {
this._lineBreak = lineBreak;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
Expand Down
27 changes: 24 additions & 3 deletions src/main/java/com/imsweb/x12/mapping/LoopDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
package com.imsweb.x12.mapping;

import java.util.List;
import java.util.Objects;

import com.imsweb.x12.mapping.TransactionDefinition.Usage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

import com.imsweb.x12.mapping.TransactionDefinition.Usage;

@XStreamAlias("loop")
public class LoopDefinition {
public class LoopDefinition implements Positioned {

@XStreamAlias("xid")
@XStreamAsAttribute
Expand All @@ -37,6 +37,7 @@ public class LoopDefinition {
@XStreamImplicit
private List<LoopDefinition> _loop;

@Override
public String getXid() {
return _xid;
}
Expand All @@ -49,6 +50,7 @@ public Usage getUsage() {
return _usage;
}

@Override
public String getPos() {
return _pos;
}
Expand All @@ -69,4 +71,23 @@ public List<LoopDefinition> getLoop() {
return _loop;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LoopDefinition that = (LoopDefinition) o;
return Objects.equals(_xid, that._xid) &&
Objects.equals(_type, that._type) &&
_usage == that._usage &&
Objects.equals(_pos, that._pos) &&
Objects.equals(_repeat, that._repeat) &&
Objects.equals(_name, that._name) &&
Objects.equals(_segment, that._segment) &&
Objects.equals(_loop, that._loop);
}

@Override
public int hashCode() {
return Objects.hash(_xid, _type, _usage, _pos, _repeat, _name, _segment, _loop);
}
}
17 changes: 17 additions & 0 deletions src/main/java/com/imsweb/x12/mapping/Positioned.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.imsweb.x12.mapping;

import java.util.Objects;

public interface Positioned extends Comparable<Positioned> {
String getXid();
String getPos();

@Override
default int compareTo(Positioned o) {
Objects.requireNonNull(o);
if (getPos().equals(o.getPos())) {
return getXid().compareTo(o.getXid());
}
return getPos().compareTo(o.getPos());
}
}
27 changes: 24 additions & 3 deletions src/main/java/com/imsweb/x12/mapping/SegmentDefinition.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@
package com.imsweb.x12.mapping;

import java.util.List;
import java.util.Objects;

import com.imsweb.x12.mapping.TransactionDefinition.Usage;
import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

import com.imsweb.x12.mapping.TransactionDefinition.Usage;

@XStreamAlias("segment")
public class SegmentDefinition {
public class SegmentDefinition implements Positioned {

@XStreamAlias("xid")
@XStreamAsAttribute
Expand All @@ -37,6 +37,7 @@ public class SegmentDefinition {
@XStreamImplicit
private List<CompositeDefinition> _composites;

@Override
public String getXid() {
return _xid;
}
Expand All @@ -49,6 +50,7 @@ public Usage getUsage() {
return _usage;
}

@Override
public String getPos() {
return _pos;
}
Expand All @@ -69,4 +71,23 @@ public List<CompositeDefinition> getComposites() {
return _composites;
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
SegmentDefinition that = (SegmentDefinition) o;
return Objects.equals(_xid, that._xid) &&
Objects.equals(_name, that._name) &&
_usage == that._usage &&
Objects.equals(_pos, that._pos) &&
Objects.equals(_maxUse, that._maxUse) &&
Objects.equals(_syntax, that._syntax) &&
Objects.equals(_elements, that._elements) &&
Objects.equals(_composites, that._composites);
}

@Override
public int hashCode() {
return Objects.hash(_xid, _name, _usage, _pos, _maxUse, _syntax, _elements, _composites);
}
}
Loading