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.
Related
Below is My method defination for kafka listener and if receive null or empty string for payload i guess I'm getting below error... Can you please help.
#KafkaListener(topics = "${kafka.consumer-topic-name.reservation}", groupId = "${kafka.consumer-group-id.test}",
containerFactory = "kafkaListenerContainerFactory",autoStartup = "${kafka.auto-start.consumer.tets}")
public void consumeReservation(String payload, #Header(KafkaHeaders.RECEIVED_TOPIC) String topic,
#Header(KafkaHeaders.RECEIVED_MESSAGE_KEY) String kafkaKey) {}
[org.springframework.kafka.KafkaListenerEndpointContainer #0-0-C-1] ERROR o.s.k.l.SeekToCurrentErrorHandler - Backoff none exhausted for ConsumerRecord(topic = test_topic, partition = 0, leaderEpoch = 2, offset = 453473, CreateTime = 1601962346576, serialized key size = 41, serialized value size = -1, headers = RecordHeaders(headers = [RecordHeader(key = OPERATION, value = [68, 69, 76, 69, 84, 69]), RecordHeader(key = __Key_TypeId__, value = [99, 108, 75, 101, 121])], isReadOnly = false), key = {
"orgId": "1",
"orderId": "U4000024004"}, value = null)
org.springframework.kafka.listener.ListenerExecutionFailedException: Listener method could not be invoked with the incoming message
Endpoint handler details:
Method[public void com.demo.test.analytics.testanalytics.consumer.FLReservationKafkaConsumer.consumeReservation(java.lang.String, java.lang.String, java.lang.String)]
Bean[com.demo.test.analytics.testanalytics.consumer.FLReservationKafkaConsumer #731702d1];
nested exception is org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException: Could not resolve method parameter at index 0 in public void com.demo.test.analytics.testanalytics.consumer.FLReservationKafkaConsumer.consumeReservation(java.lang.String, java.lang.String, java.lang.String): 1 error(s): [Error in object 'payload': codes[];arguments[];
default message[Payload value must not be empty]
], failedMessage = GenericMessage[payload = org.springframework.kafka.support.KafkaNull #2d99561c, headers = {
Key_TypeId = [B #19a2dc5f, kafka_offset = 453473, OPERATION = [B #7d75c01a, kafka_consumer = org.apache.kafka.clients.consumer.KafkaConsumer #363f44ef, kafka_timestampType = CREATE_TIME, kafka_receivedPartitionId = 0, kafka_receivedMessageKey = {
"orgId": "1",
"orderId": "U4000024004"
}, kafka_receivedTopic = test_1order, kafka_receivedTimestamp = 1601962346576, kafka_groupId = reservation_group_id
}];nested exception is org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException: Could not resolve method parameter at index 0 in public void com.demo.test.analytics.testanalytics.consumer.FLReservationKafkaConsumer.consumeReservation(java.lang.String, java.lang.String, java.lang.String): 1 error(s): [Error in object 'payload': codes[];arguments[];
default message[Payload value must not be empty]
],
failedMessage = GenericMessage[payload = org.springframework.kafka.support.KafkaNull #2d99561c, headers = {
Key_TypeId = [B #19a2dc5f, kafka_offset = 453473, OPERATION = [B #7d75c01a, kafka_consumer = org.apache.kafka.clients.consumer.KafkaConsumer #363f44ef, kafka_timestampType = CREATE_TIME, kafka_receivedPartitionId = 0, kafka_receivedMessageKey = {
"orgId": "1",
"orderId": "U4000024004"
}, kafka_receivedTopic = test_1order, kafka_receivedTimestamp = 1601962346576, kafka_groupId = reservation_group_id
}]
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.decorateException(KafkaMessageListenerContainer.java: 1925)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeErrorHandler(KafkaMessageListenerContainer.java: 1913)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java: 1812)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeWithRecords(KafkaMessageListenerContainer.java: 1739)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeRecordListener(KafkaMessageListenerContainer.java: 1636)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeListener(KafkaMessageListenerContainer.java: 1366)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.pollAndInvoke(KafkaMessageListenerContainer.java: 1082)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.run(KafkaMessageListenerContainer.java: 990)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java: 511)
at java.util.concurrent.FutureTask.run(FutureTask.java: 266)
at java.lang.Thread.run(Thread.java: 748)
Caused by: org.springframework.messaging.handler.annotation.support.MethodArgumentNotValidException: Could not resolve method parameter at index 0 in public void com.demo.test.analytics.testanalytics.consumer.FLReservationKafkaConsumer.consumeReservation(java.lang.String, java.lang.String, java.lang.String): 1 error(s): [Error in object 'payload': codes[];arguments[];
default message[Payload value must not be empty]
]
at org.springframework.messaging.handler.annotation.support.PayloadMethodArgumentResolver.resolveArgument(PayloadMethodArgumentResolver.java: 122)
at org.springframework.kafka.annotation.KafkaListenerAnnotationBeanPostProcessor$KafkaNullAwarePayloadArgumentResolver.resolveArgument(KafkaListenerAnnotationBeanPostProcessor.java: 901)
at org.springframework.messaging.handler.invocation.HandlerMethodArgumentResolverComposite.resolveArgument(HandlerMethodArgumentResolverComposite.java: 117)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.getMethodArgumentValues(InvocableHandlerMethod.java: 148)
at org.springframework.messaging.handler.invocation.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java: 116)
at org.springframework.kafka.listener.adapter.HandlerAdapter.invoke(HandlerAdapter.java: 48)
at org.springframework.kafka.listener.adapter.MessagingMessageListenerAdapter.invokeHandler(MessagingMessageListenerAdapter.java: 329)
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java: 86)
at org.springframework.kafka.listener.adapter.RecordMessagingMessageListenerAdapter.onMessage(RecordMessagingMessageListenerAdapter.java: 51)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeOnMessage(KafkaMessageListenerContainer.java: 1880)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.invokeOnMessage(KafkaMessageListenerContainer.java: 1862)
at org.springframework.kafka.listener.KafkaMessageListenerContainer$ListenerConsumer.doInvokeRecordListener(KafkaMessageListenerContainer.java: 1799)
...8 common frames omitt
You need to specify that the payload is not required.
#Payload(required = false) String payload, ...
I want filter the messages with type X from table below whose TO value is not equal to FROM value of any Type Y records in same table. (eg. ee) using Linq.
Message TO FROM Type
------- ---- ----- ------
aa 11 22 X
bb 33 44 X
cc 55 11 Y
dd 66 33 Y
ee 77 88 X
I have used this but not working
var messages1 = messages.Where(x => x.Type == 'X');
var messages2 = messages.Where(x => x.Type == 'Y');
var filteredMessages = messages1
.Where(x => !messages2.Any(y => y.From == x.To));
I am not able to reproduce your issue, although I am getting the correct output.
private static void Main(string[] args)
{
List<MessageItem> messages = new List<MessageItem>
{
new MessageItem
{
Message = "aa",
From = 22,
To = 11,
Type = "X"
},
new MessageItem
{
Message = "bb",
From = 44,
To = 33,
Type = "X"
},
new MessageItem
{
Message = "cc",
From = 11,
To = 55,
Type = "Y"
},
new MessageItem
{
Message = "dd",
From = 33,
To = 66,
Type = "Y"
},
new MessageItem
{
Message = "ee",
From = 88,
To = 77,
Type = "X"
}
};
var messages1 = messages.Where(x => x.Type == "X").ToList();
var messages2 = messages.Where(x => x.Type == "Y").ToList();
var filteredMessages = messages1.FindAll(x => !messages2.Any(y => x.To == y.From));
}
The model class:
public class MessageItem
{
public string Message { get; set; }
public int From { get; set; }
public int To { get; set; }
public string Type { get; set; }
}
Outputting:
I've 4 tables Transactions, Attachment, SubReportType & SubRepRole. I'm having user roles on my Cache. I want to have those attachments which are related with User roles[a user may have multiple role]
List<int> userrole = new List<int>();
UserContext user_details = (UserContext)HttpContext.Current.Cache["UserContext"];
IList<UserRole> userrole_id = user_details.UserRoleModuleWise;
var query = (from trans in objContext.Transactions
join attch in objContext.Attachment on trans.TransId equals attch.TransId
join subrept in objContext.SubReportType on trans.SubRepId equals subrept.SubRepId
join subreprl in objContext.SubRepRole on trans.SubRepId equals subreprl.SubRepId
join selectedrole in userrole_id on subreprl.RoleId equals selectedrole.RoleId
/*where obj.Contains(subreprl.RoleId) */orderby trans.TransDate
select new AttachmentModel
{
Createdate = attch.CreatedDateTime,
FileType = attch.FileType,
FileName = attch.FileName,
Attachid = attch.AttachedId,
FileTag = attch.FileTag,
Transid = trans.TransId,
SubReportName = subrept.SubRepName,
RandomPinNo = attch.FileRandomPin
}).ToList();
Now getting this error:
Unable to create a constant value of type
'User.Common.DataContract.UserRole'. Only primitive types or
enumeration types are supported in this context.
Please help on this. Tried "Contains" too but type casting error is coming. Just wanted to have those records where roles are in user_details.UserRoleModuleWise. user_details.UserRoleModuleWise is an array with RoleId and RoleName
You need to use Contains with an array of the correct values:
where user_details.UserRoleModuleWise.Select(urmw => urmw.RoleId).ToArray().Contains(aRoleId => aRoleId == subreprl.RoleId)
Created a common class --
object[] common_data = new object[4];
UserContext user_details = (UserContext)HttpContext.Current.Cache["UserContext"];
List<UserRole> userrole_id = user_details.UserRoleModuleWise.ToList();
int[] roleid = { -1, -2, -3, -4, -5, -6, -7, -8, -9, -10, -11, -12, -13, -14, -15, -16, -17, -18, -19, -20 };
string[] rolename = { "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "" };
for (int i = 0; i < userrole_id.Count; i++)
{
roleid[i] = Convert.ToInt32(userrole_id[i].RoleId);
rolename[i] = Convert.ToString(userrole_id[i].RoleName);
r_id.Add(roleid[i], rolename[i]);
}
common_data[0] = roleid;
common_data[1] = rolename;
//common_data[2] = username;
common_data[3] = userrole_id.Count;
then in my repository i used -
User_common_data ucd = new User_common_data();
object[] ucd_data = ucd.user_common_details();
int[] roles = (int[]) ucd_data[0];
var query = (from obj in objContext.ReportType
join obj1 in objContext.SubReportType on obj.RepId equals obj1.RepId
join obj2 in objContext.SubRepRole on obj1.SubRepId equals obj2.SubRepId
where roles.Contains(obj2.RoleId)
select new ReportTypeModel
{
RepId = obj.RepId,
RepName = obj.RepName,
RepCode = obj.RepCode
}).ToList();
now its working fine. #NetMage's answer also worked... thanks
I got result after executing linq query in mvc like below:
[0] = { albumid = 176, selecttionid = 243, orderid = 57 }
[1] = { albumid = 177, selecttionid = 243, orderid = 57 }
[2] = { albumid = 178, selecttionid = 243, orderid = 57 }
[3] = { albumid = 19, selecttionid = 321, orderid = 137 }
......
But I need to create folder for each different selecttionid .How can I do this?
If you just need to create a folder for each diferente selecttionid, than you just need use Select with Distinct, like that:
var selections = mylist.Select(x => x.selecttionid).Distinct();
foreach(var selection in selections)
{
//Code that create a folder for the selectionId
}
If you need the values from the list, than you can use GroupBy.
var groupedSelections = mylist.GroupBy(x => x.selecttionid);
foreach(var groupSelecion in groupedSelections)
{
//Code that create a folder for the groupSelecion.Key
}
I have enum code here.
public enum SCode
{
F101 = 1,
F110 = 2,
F112 = 3,
F153 = 4,
F154 = 5,
F155 = 6,
F156 = 7,
F301 = 8,
F302 = 9,
F303 = 10,
F304 = 11,
F305 = 12,
F306 = 13,
F307 = 14,
F308 = 15,
F309 = 16,
F310 = 17,
F311 = 18,
F319 = 19,
}
I already fix it on number. But I don't need to fix it. I need to use enum as parameter. Can I use like this?
public enum SCode
{
cmd = code,
}
code is the variable that can be change anytime.
Thanks for answer and make me clear.
You cannot provide variables to your enumerations. They have to have a static value. You can provide something like this:
public enum SCode
{
F100, -- its value will be 0
F200 -- its value will be 1
}
or
public enum SCode
{
F100 = 14, -- its value will be 14
F200 -- its value will be 15
}
but you cannot provide a variable like this:
var employeeID = 14;
public enum SCode
{
F100 = employeeID, -- won't work
F200
}