I am new to Bean-IO and I was trying to configure a validation logic for occurrence of group when a particular record type is available in the file. For example if there are three records in flat file as shown below.
560866
670972
57086659
I am trying to setup the following logic
Both 56 and 67 lines together form a multi line record
56&67 records can come independently of record 57,but 57 record cannot come without 56&67.
I was successful in creating the first validation using minOccurs attribute in #record annotation, but was not able to do the same for 56&67 using a group.
Please find the sample code setup below.
HeaderRecord class holds the 56&67 record details
#Group
public class HeaderRecord {
#Record(minOccurs = 1)
public TX56 tx56;
#Record(minOccurs = 1)
public TX67 tx67;
}
RecordObject is used to hold the headers and line items
public class RecordObject {
#Group(collection = List.class, minOccurs = 1)
List<HeaderRecord> headerRecords;
#Record(collection = List.class)
List<TX57> tx57s;
}
#Record(maxLength = 10, name = "TX56")
public class TX56 {
#Field(ordinal = 0, at = 0, length = 2, rid = true, literal = "56", trim = true)
protected int id;
#Field(ordinal = 1, at = 2, length = 4, trim = true)
protected int number;
}
#Record(maxLength = 31, name = "TX67")
public class TX67 {
#Field(ordinal = 0, at = 0, length = 2, rid = true, literal = "67", trim = true)
protected int id;
#Field(ordinal = 1, at = 2, length = 4, trim = true)
protected int number;
}
#Record(maxLength = 71, name = "TX57")
public class TX57 {
#Field(ordinal = 0, at = 0, length = 2, rid = true, literal = "57", trim = true)
protected int id;
#Field(ordinal = 1, at = 2, length = 4, trim = true)
protected int number;
}
with the above configuration when I try to parse the file with records given below, it throws UnexpectedRecordException.
560866
670972
57086659
Stack trace:
2018-07-17 15:22:07,778[http-nio-8080-exec-2]ERROR
org.apache.catalina.core.ContainerBase.[Tomcat].[localhost].[/].[dispatcherServlet]-Servlet.service()for
servlet[dispatcherServlet]in context with path[]threw
exception[Request processing failed;nested exception is
org.beanio.UnexpectedRecordException:End of stream reached,expected
record'tx56']with root cause org.beanio.UnexpectedRecordException:End
of stream reached,expected record'tx56' at
org.beanio.internal.parser.UnmarshallingContext.newUnsatisfiedRecordException(UnmarshallingContext.java:367)~[beanio-2.1.0.jar:2.1.0]
at
org.beanio.internal.parser.Group.unmarshal(Group.java:127)~[beanio-.1.0.jar:2.1.0]
at
org.beanio.internal.parser.DelegatingParser.unmarshal(DelegatingParser.java:39)~[beanio-2.1.0.jar:2.1.0]
at
org.beanio.internal.parser.RecordCollection.unmarshal(RecordCollection.java:42)~[beanio-2.1.0.jar:2.1.0]
at
org.beanio.internal.parser.Group.unmarshal(Group.java:118)~[beanio-2.1.0.jar:2.1.0]
at
org.beanio.internal.parser.BeanReaderImpl.internalRead(BeanReaderImpl.java:106)~[beanio-2.1.0.jar:2.1.0]
at
org.beanio.internal.parser.BeanReaderImpl.read(BeanReaderImpl.java:67)~[beanio-2.1.0.jar:2.1.0]
at
dk.coop.integration.fileconversion.service.sampleapplication.createFixedLengthFile(sampleapplication.java:32)~[classes/:?]
Note:
with the above configuration, following scenarios works
56&67comes independently
560866
670972
57cannot come independently
57086659:this flat file fails with a proper exception
56&67should always come as a single record.
this also works fine.
Additional Details:
Sample Flatfile
560866
670972
560866
670972
560866
670972
57086659
57086659
57086659
57086659
52022
560866
670972
57086659
As seen above, in the flat file there is a possibility that multiple header records and TX57 record can come as a single entity. Also there can be other type of records that can come in between, in which case I have to treat second occurrence of TX56,67 and 57 as a different item.
In the above example first 10 records will form a single recordObject, then the second occurrence of these records will form a second record object. Sorry for not sharing earlier, but there is another wrapper class which holds a list of recordObject.
I am giving the working maven project Github URL below. https://github.com/Jayadeep2308/FlatFileParser
EDIT: Updated after all requirements on 5 Aug 2018
I have made all the fields private inside the classes and assume that you have the getters + setters in place.
I have tried various combinations of settings on the #Group and #Record annotations so the code below might not be optimal, but should work.
First the main group (WrapperObject) that holds all your data:
#Group(minOccurs = 1, maxOccurs = 1)
public class WrapperObject {
#Group(minOccurs = 0, maxOccurs = 1, collection = List.class)
private List<RecordObject> recordObjectList;
#Record(minOccurs = 0, maxOccurs = -1, collection = List.class)
private List<TX52> tx52s;
}
EDIT: RecordObject updated to hold a list of HeaderRecord, also changed the #Group values.
#Group(minOccurs = 0, maxOccurs = -1)
public class RecordObject {
#Group(minOccurs = 0, maxOccurs = -1, collection = List.class)
private List<HeaderRecord> headerRecords;
#Record(minOccurs = 0, maxOccurs = -1, collection = List.class)
private List<TX57> tx57s;
}
#Group(minOccurs = 0, maxOccurs = -1)
public class HeaderRecord {
#Record(minOccurs = 1, maxOccurs = 1)
private TX56 tx56;
#Record(minOccurs = 1, maxOccurs = 1)
private TX67 tx67;
}
On the individual TX records I have added the required=true attribute on the #Field annotation for your record identifier fields.
Edit: Added TX52
#Record(maxLength = 74, name = "TX52")
public class TX52 {
#Field(ordinal = 0, at = 0, length = 2, rid = true, literal = "52", trim = true, required = true)
private int id;
#Field(ordinal = 1, at = 2, length = 3, trim = true)
private int number;
}
#Record(maxLength = 10, name = "TX56")
public class TX56 {
#Field(ordinal = 0, at = 0, length = 2, rid = true, literal = "56", trim = true, required = true)
private int id;
#Field(ordinal = 1, at = 2, length = 4, trim = true, required = true)
private int number;
}
#Record(maxLength = 31, name = "TX67")
public class TX67 {
#Field(ordinal = 0, at = 0, length = 2, rid = true, literal = "67", trim = true, required = true)
private int id;
#Field(ordinal = 1, at = 2, length = 4, trim = true)
private int number;
}
#Record(maxLength = 71, name = "TX57")
public class TX57 {
#Field(ordinal = 0, at = 0, length = 2, rid = true, literal = "57", trim = true, required = true)
private int id;
#Field(ordinal = 1, at = 2, length = 4, trim = true)
private int number;
}
Lastly, my test code: (EDIT: Updated test data)
#Test
public void test() {
final StreamFactory factory = StreamFactory.newInstance();
final StreamBuilder builder = new StreamBuilder("Jaydeep23")
.format("fixedlength")
.parser(new FixedLengthParserBuilder())
.addGroup(WrapperObject.class);
factory.define(builder);
final String scenario1 = "560866\n670972\n560866\n670972\n560866\n670972";
final String scenario2 = "560866\n670972\n560866\n670972\n560866\n670972\n57086659\n57086659\n57086659\n" +
"57086659\n560866\n670972\n57086659\n560866\n670972";
// invalid
final String scenario3 = "57086659\n57086659\n57086659\n57086659\n57086659";
final String scenario4 = "52022\n52066\n52054\n52120";
final String scenario5 = scenario1;
final String scenario6 = "560866\n670972\n560866\n670972\n560866\n670972\n57086659\n57086659\n57086659\n" +
"57086659\n52021\n52022\n52023\n560866\n670972\n57086659\n52023";
final String message = scenario1;
BeanReader beanReader = null;
Object object = null;
try (final Reader in = new BufferedReader(new StringReader(message))) {
beanReader = factory.createReader("Jaydeep23", in);
beanReader.setErrorHandler(new LoggingBeanReaderErrorHandler());
while ((object = beanReader.read()) != null) {
System.out.println("Object = " + object);
}
} catch (final Exception e) {
fail(e.getMessage());
} finally {
if (beanReader != null) {
beanReader.close();
}
}
}
Generates this output: (EDIT: using your toString() methods)
Scenario 1 = [[Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
, Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
, Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
]null]null
Scenario 2 = [[Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
, Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
, Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
, Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
, Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
][Record Type = 57, Store Number = 866
, Record Type = 57, Store Number = 866
, Record Type = 57, Store Number = 866
, Record Type = 57, Store Number = 866
, Record Type = 57, Store Number = 866
]]null
Scenario 3 - gives this error (which is correct according as TX57 is not allowed on its own:
Expected record/group 'tx56' at line 6
Scenario 4 = null[Record Type = 52, Store Number = 22
, Record Type = 52, Store Number = 66
, Record Type = 52, Store Number = 54
, Record Type = 52, Store Number = 120
]
Scenario 5 = [[Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
, Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
, Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
]null]null
Scenario 6 = [[Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
, Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
, Record Type = 56, Store Number = 866
Record Type = 67, Store Number = 972
][Record Type = 57, Store Number = 866
, Record Type = 57, Store Number = 866
, Record Type = 57, Store Number = 866
, Record Type = 57, Store Number = 866
]][Record Type = 52, Store Number = 21
, Record Type = 52, Store Number = 22
, Record Type = 52, Store Number = 23
]
Hope this helps.
Let me know if it is now working for you.
For example, I have source code
enum ColorModel
{
COLOR_MODEL_RGB = 0,
COLOR_MODEL_RGBA = 1,
COLOR_MODEL_Grayscale = 2,
COLOR_MODEL_GrayscaleAlpha = 3,
COLOR_MODEL_CMYK = 4,
};
And after generation, in Enumerations section I get:
enum EColorModel {
COLOR_MODEL_RGB = 0, COLOR_MODEL_RGBA = 1, COLOR_MODEL_Grayscale = 2, COLOR_MODEL_GrayscaleAlpha = 3, COLOR_MODEL_CMYK = 4
}
How can I hide values to get just
enum EColorModel {
COLOR_MODEL_RGB,
COLOR_MODEL_RGBA,
COLOR_MODEL_Grayscale,
COLOR_MODEL_GrayscaleAlpha,
COLOR_MODEL_CMYK,
}
Set the following in doxygen's configuration file:
MAX_INITIALIZER_LINES = 0
Q1: What is better shorthand version of the following?
Q2: How can I pass anonymous types to my view in mvc3?
public ViewResult Index3()
{
List<T1> ls = new List<T1>();
ls.Add(new T1 { id = 1, title = "t1", val1 = 1, val2 = 2});
ls.Add(new T1 {id=2, title="t2", val1=3, val2=4});
ls.Add(new T1 { id = 3, title = "t3", val1 = 5, val2 = 6});
return View(ls);
}
(Q1) Something similar to?:
List<T1> ls = new List<T1>(
List<T1>(new { id = 1, title = "t1", val1 = 1, val2 = 2}
new { id = 2, title = "t2", val1 = 3, val2 = 4})
);
(Q2) Something similar to?:
public ViewResult Index3()
{
return View(List(new { id = 1, title = "t1", val1 = 1, val2 = 2 }
new { id = 2, title = "t2", val2 = 3, val2 = 4 }
);
}
Then reference the above in the razor view:
#model IEnumerable<Some Anonymous or Dynamic Model>
#item.id
#item.title
#item.val1
...
Q1 is a matter of preference. There is no performance difference as the compiler internally creates similar code.
Q2 is impossible, you must create a non-anonymous type to be able to access it.
Could use ViewBag to pass your list to the view.
Collection initializers are written like this:
List<T1> ls = new List<T1> {
new T1 { id = 1, title = "t1", val1 = 1, val2 = 2 },
new T1 { id = 2, title = "t2", val1 = 3, val2 = 4 },
new T1 { id = 3, title = "t3", val1 = 5, val2 = 6 }
};
Create an implicitly-typed array:
return View(new [] { new { id = 1, ... }, ... });
Neither option will work as anonymous types are internal and razor views are compiled into a separate assembly.
See:
Dynamic view of anonymous type missing member issue - MVC3
My manager has pointed out to me a few nifty things that one of our accounting applications can do because it can load different settings based on the machine name of the host and the machine name of the client when the package is opened in an RDP session.
We want to provide similar functionality in one of my company's applications.
I've found out on this site how to detect if I'm in an RDP session, but I'm having trouble finding information anywhere on how to detect the name of the client computer.
Any pointers in the right direction would be great.
I'm coding in C# for .NET 3.5
EDIT
The sample code I cobbled together from the advice below - it should be enough for anyone who has a use for the WTSQuerySessionInformation to get a feel for what's going on. Note that this isn't necessarily the best way of doing it - just a starting point that I've found useful.
When I run this locally, I get boring, expected answers. When I run it on our local office server in an RDP session, I see my own computer name in the WTSClientName property.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
namespace TerminalServicesTest
{
class Program
{
const int WTS_CURRENT_SESSION = -1;
static readonly IntPtr WTS_CURRENT_SERVER_HANDLE = IntPtr.Zero;
static void Main(string[] args)
{
StringBuilder sb = new StringBuilder();
uint byteCount;
foreach (WTS_INFO_CLASS item in Enum.GetValues(typeof(WTS_INFO_CLASS)))
{
Program.WTSQuerySessionInformation(
WTS_CURRENT_SERVER_HANDLE,
WTS_CURRENT_SESSION,
item,
out sb,
out byteCount);
Console.WriteLine("{0}({1}): {2}", item.ToString(), byteCount, sb);
}
Console.WriteLine();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
[DllImport("Wtsapi32.dll")]
public static extern bool WTSQuerySessionInformation(
IntPtr hServer, int sessionId, WTS_INFO_CLASS wtsInfoClass, out StringBuilder ppBuffer, out uint pBytesReturned);
}
enum WTS_INFO_CLASS
{
WTSInitialProgram = 0,
WTSApplicationName = 1,
WTSWorkingDirectory = 2,
WTSOEMId = 3,
WTSSessionId = 4,
WTSUserName = 5,
WTSWinStationName = 6,
WTSDomainName = 7,
WTSConnectState = 8,
WTSClientBuildNumber = 9,
WTSClientName = 10,
WTSClientDirectory = 11,
WTSClientProductId = 12,
WTSClientHardwareId = 13,
WTSClientAddress = 14,
WTSClientDisplay = 15,
WTSClientProtocolType = 16,
WTSIdleTime = 17,
WTSLogonTime = 18,
WTSIncomingBytes = 19,
WTSOutgoingBytes = 20,
WTSIncomingFrames = 21,
WTSOutgoingFrames = 22,
WTSClientInfo = 23,
WTSSessionInfo = 24,
WTSSessionInfoEx = 25,
WTSConfigInfo = 26,
WTSValidationInfo = 27,
WTSSessionAddressV4 = 28,
WTSIsRemoteSession = 29
}
}
Have you checked into the WTS_INFO_CLASS enum?
You can obtain this information by calling: WTSQuerySessionInformation.
I'm not sure of the exact value listed in WTS_INFO_CLASS that you need, but it looks like: WTSClientName.
You could also use the Cassia library for this if you don't want to deal with the P-Invokes -- the code would be:
new TerminalServicesManager().CurrentSession.ClientName
Here is my code
if (catid != 0)
posts = posts.Where(x => x.catid IN '1,8,2,109,23');
The in in this code shows as a syntax error. Is there a way to fix this
You must use another list to compare too.
List<int> cadIdFoundList = new List<int>();
cadIdFoundList.Add(1);
cadIdFoundList.Add(8);
// etc. . .
posts.Where(x => cadIdFoundList.Contains(x.catId));
int[] ids = new int[] { 1, 8, 2, 109, 23 };
var query = posts.Where(x => ids.Contains(x.catid));
Rob Conery has discussed this topic before.
Or even more simple:
var query = posts.Where(x => new[] { 1, 8, 2, 109, 23 }.Contains(x.catid));
Maybe something more like:
HashSet<int> categories = new HashSet<int>() { 1, 2, 8, 23, 109};
posts = posts.Where(post => categories.Contains(post.catid));