Java 8 -> Collectors.toMap -> Duplicate key - java-8

I m trying to convert List of available Currency to a Map, To look up based on Currency Numeric code i want to get String code. Here is the code.
But this code above throwing below error, I m very new to Java 8 hence banging my head :
Exception in thread "main" java.lang.ExceptionInInitializerError
Caused by: java.lang.IllegalStateException: Duplicate key YUM
at java.util.stream.Collectors.lambda$throwingMerger$0(Collectors.java:133)
at java.util.HashMap.merge(HashMap.java:1254)
at java.util.stream.Collectors.lambda$toMap$58(Collectors.java:1320)
at java.util.stream.ReduceOps$3ReducingSink.accept(ReduceOps.java:169)
at java.util.HashMap$KeySpliterator.forEachRemaining(HashMap.java:1556)
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:708)
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:499)
But this code above throwing below error, I m very new to Java 8 hence banging my head
public class IsoCurrencyCode {
private static final Set<Currency> ISO_CURRENCY = Currency.getAvailableCurrencies();
private static final Map<Integer, Currency> NUMERIC_MAP = ISO_CURRENCY.stream().collect(Collectors.toMap(Currency::getNumericCode, Function.identity()));
public static void main(String[] args) {
//
Currency currency = NUMERIC_MAP.get(971);
System.out.println(currency.getCurrencyCode());
}
}
It should load all currencies into the map with code as keys.

Collectors.toMap() doesn't accept duplicates for keys.
Since you have that for Currency::getNumericCode, toMap() throws this exception when a duplicate key is encountered.
Caused by: java.lang.IllegalStateException: Duplicate key YUM
Note that here the error message is misleading. Keys are Integer while YUM is not. YUM looks like a Currency instance and that is.
Indeed, YUM refers to one of the values (Currency) processed by toMap() that have a duplicate key, not the key value itself. It is a Java bug fixed in Java 9.
To solve your issue, either use Collectors.groupingBy() to collect to a Map<Integer, List<Currency>> and in this case you could have multiple values by key or as alternative merge the duplicate keys with the toMap() overload, for example to keep the last entry :
private static final Map<Integer, Currency> NUMERIC_MAP =
ISO_CURRENCY.stream()
.collect(Collectors.toMap(Currency::getNumericCode, Function.identity(), (v1, v2)-> v2);
To answer to your comment, you could find the culprit code (duplicates) in this way :
Map<Integer, List<Currency>> dupMap =
ISO_CURRENCY.stream()
.collect(Collectors.groupingBy(Currency::getNumericCode)
.entrySet()
.filter(e -> e.getValue().size() > 1)
.collect(Collectors.toMap(Entry::getKey,Entry::getValue));
System.out.println(dupMap);

Related

FlatFileParseException while parsing csv file to dump data in MySQL using Spring Batch

I am trying to dump data from csv to MySQL using Spring Batch. But on running the application, the following error is encountered:
org.springframework.batch.item.file.FlatFileParseException: Parsing error at line: 2 in resource=[class path resource [People2.csv]], input=[aardsda01,1981,12,27,USA,CO,Denver,2022,2,22,USA,NJ,Atlanta,David,Aardsma,David Allan,215,75,R,R,06-04-2004,23-08-2015,aardd001,aardsda01]
at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:194) ~[spring-batch-infrastructure-5.0.0.jar:5.0.0]
at org.springframework.batch.item.support.AbstractItemCountingItemStreamItemReader.read(AbstractItemCountingItemStreamItemReader.java:95) ~[spring-batch-infrastructure-5.0.0.jar:5.0.0]
at org.springframework.batch.core.step.item.SimpleChunkProvider.doRead(SimpleChunkProvider.java:110) ~[spring-batch-core-5.0.0.jar:5.0.0]
at org.springframework.batch.core.step.item.SimpleChunkProvider.read(SimpleChunkProvider.java:189) ~[spring-batch-core-5.0.0.jar:5.0.0]
at org.springframework.batch.core.step.item.SimpleChunkProvider$1.doInIteration(SimpleChunkProvider.java:137) ~[spring-batch-core-5.0.0.jar:5.0.0]
...............
Caused by: org.springframework.batch.item.file.transform.IncorrectTokenCountException: Incorrect number of tokens found in record: expected 24 actual 7
at org.springframework.batch.item.file.transform.AbstractLineTokenizer.tokenize(AbstractLineTokenizer.java:133) ~[spring-batch-infrastructure-5.0.0.jar:5.0.0]
at org.springframework.batch.item.file.mapping.DefaultLineMapper.mapLine(DefaultLineMapper.java:42) ~[spring-batch-infrastructure-5.0.0.jar:5.0.0]
at org.springframework.batch.item.file.FlatFileItemReader.doRead(FlatFileItemReader.java:190) ~[spring-batch-infrastructure-5.0.0.jar:5.0.0]
... 41 common frames omitted
The ItemReader and ItemWriter Beans are:
#Bean
public FlatFileItemReader<Player> reader()
{
FlatFileItemReader<Player> reader=new FlatFileItemReader<Player>();
reader.setResource(new ClassPathResource("People2.csv"));
reader.setLineMapper(getLineMapper());
reader.setLinesToSkip(1);//Skip line in case of error
return reader;
}
private LineMapper<Player> getLineMapper() {
DefaultLineMapper<Player> lineMapper
=new DefaultLineMapper<Player>();
DelimitedLineTokenizer lineTokenizer=new DelimitedLineTokenizer();
lineTokenizer.setNames(new String[] {"playerID","birthYear","","","","","birthCity","","","","","","","nameFirst","nameLast","","","","","","","","retroID","bbrefID"});//name of field to be taken out. Empty string are columns which has to be skipped
lineTokenizer.setIncludedFields(new int[] {0,1,6,13,14,22,23});
BeanWrapperFieldSetMapper<Player> fieldSetMapper=new BeanWrapperFieldSetMapper<Player>();
fieldSetMapper.setTargetType(Player.class);
lineMapper.setLineTokenizer(lineTokenizer);
lineMapper.setFieldSetMapper(fieldSetMapper);
return lineMapper;
}
Spring Boot version I am using is 3.0.1
Incorrect number of tokens found in record: expected 24 actual 7 means you have less tokens in your input line than it is expected by your batch job.
In fact, you declared 24 names in lineTokenizer.setNames, but only included 7 in lineTokenizer.setIncludedFields. Those two parameters should match. You should think of it like: "Please include only these fields, and here are their names".
If you remove those empty "" (no need for them) and your input line has exactly 7 columns, then this error should not happen.

SpringBoot: EL1003E property values casting

I have a Spring Boot config file with this values:
#Value("#{new Integer('${db.pool.size}')}")
private Integer dbPoolSize;
#Value("#{new Integer('${db.minimum.idle}')}")
private Integer dbMinimumIdle;
But when I start the application I got this error:
Caused by: org.springframework.expression.spel.SpelEvaluationException: EL1003E: A problem occurred whilst attempting to construct an object of type 'Integer' using arguments '(java.lang.String)'
at org.springframework.expression.spel.ast.ConstructorReference.createNewInstance(ConstructorReference.java:168) ~[spring-expression-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.expression.spel.ast.ConstructorReference.getValueInternal(ConstructorReference.java:98) ~[spring-expression-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:120) ~[spring-expression-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:242) ~[spring-expression-4.3.6.RELEASE.jar:4.3.6.RELEASE]
at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:161) ~[spring-context-4.3.6.RELEASE.jar:4.3.6.RELEASE]
... 42 common frames omitted
Imagine you have the following application.properties:
db.minimum.idle=12
db.pool.size=10
Then you should just do something like:
#Value("${db.pool.size}")
private Integer dbPoolSize;
#Value("${db.minimum.idle}")
private Integer dbMinimumIdle;
You do not have to create a new integer, that is automacally done by spring
Just use:
#Value("${db.minimum.idle}")
private Integer dbMinimumIdle;
No need to explicitly instantiate new integer using spel.

How can I use S3InboundFileSynchronizer to synchronize an S3Bucket organized with directories?

I'm trying to use the S3InboundFileSynchronizer to synchronize an S3Bucket to a local directory. The bucket is organised with sub-directories such as:
bucket ->
2016 ->
08 ->
daily-report-20160801.csv
daily-report-20160802.csv
etc...
Using this configuration:
#Bean
public S3InboundFileSynchronizer s3InboundFileSynchronizer() {
S3InboundFileSynchronizer synchronizer = new S3InboundFileSynchronizer(amazonS3());
synchronizer.setDeleteRemoteFiles(true);
synchronizer.setPreserveTimestamp(true);
synchronizer.setRemoteDirectory("REDACTED");
synchronizer.setFilter(new S3RegexPatternFileListFilter(".*\\.csv$"));
Expression expression = PARSER.parseExpression("#this.substring(#this.lastIndexOf('/')+1)");
synchronizer.setLocalFilenameGeneratorExpression(expression);
return synchronizer;
}
I'm able to get as far as connecting to the bucket and listing its contents. When it comes time to read from the bucket the following exception is thrown:
org.springframework.messaging.MessagingException: Problem occurred while synchronizing remote to local directory; nested exception is
org.springframework.messaging.MessagingException: Failed to execute on session;
nested exception is
java.lang.IllegalStateException: 'path' must in pattern [BUCKET/KEY].
at org.springframework.integration.file.remote.synchronizer.AbstractInboundFileSynchronizer.synchronizeToLocalDirectory(AbstractInboundFileSynchronizer.java:266)
Reviewing the code it seems that it'd be impossible to ever synchronize an S3Bucket w/ sub-directories:
private String[] splitPathToBucketAndKey(String path) {
Assert.hasText(path, "'path' must not be empty String.");
String[] bucketKey = path.split("/");
Assert.state(bucketKey.length == 2, "'path' must in pattern [BUCKET/KEY].");
Assert.state(bucketKey[0].length() >= 3, "S3 bucket name must be at least 3 characters long.");
bucketKey[0] = resolveBucket(bucketKey[0]);
return bucketKey;
}
Is there some configuration I'm missing or is this a bug?
(I'm assuming it's a bug 'till I'm told otherwise so I've submitted a pull request with a proposed fix.)
Yes, it is a bug and submitted PullRequest is good for fix.
Only the solution as a workaround is like custom SessionFactory<S3ObjectSummary> which returns a custom S3Session extension with the provided fix in the PR.

Appending a byte into a byte array in Java Card

I have a method below to insert a single byte into a byte buffer and during building and cleaning for a Java Card CAP file it throws an error.
Code:
private void appendOutputBuffer(byte msg) {
ArrayLogic.arrayCopyRepack(msg, (short) 0, (short) 0, outputBuffer, (short) outputBuffer.length);
}
Error:
error: line 163: sctest: class java.lang.Byte not found in export file lang.exp.
error: line 163: sctest: method valueOf(byte) of class java.lang.Byte not found in export file lang.exp or the method signature has changed.
error: line 163: sctest: class java.lang.Byte not found in export file lang.exp.
error: line 163: sctest: class java.lang.Byte in return type of method java.lang.Byte.valueOf(byte) not found.
How do I resolve it ?
This is not how arrayCopyRepack works. Read the documentation: http://www.win.tue.nl/pinpasjc/docs/apis/jc222/javacardx/framework/util/ArrayLogic.html#arrayCopyRepack%28java.lang.Object,%20short,%20short,%20java.lang.Object,%20short%29
Its signature is:
public static final short arrayCopyRepack(Object src,
short srcOff,
short srcLen,
Object dest,
short destOff)
but the src argument is meant to be an array - it is an Object just because there is no common ancestor class for all primitive arrays in Java Card. Not everything in Java Card is an Object: byte is a primitive. That causes your troubles.
The first step of Java Card build is a common Java compiler creating a standard .class file. This compiler does not know anything about Java Card and it sees a byte used as an Object, so it uses autoboxing, casting your byte to java.lang.Byte and adding a dependence to java.lang.Byte in your .class file. So far so good. This is just plain Java, so it works.
However, in Java Card libraries there is no java.lang.Byte in java.lang package. That causes the error when creating a .cap file.
Appending a byte to an existing array (and thus creating a new array) is a very bad idea, btw. You should create your buffer long enough and store the effective length (how long is the used part of the buffer):
private static final short BUF_LEN = (short) 256;
byte[] outputBuffer = new byte[BUF_LEN];
...
private void appendOutputBuffer(byte msg) {
if (effectiveLen == BUF_LEN)
ISOException.throwIt(ISO7816.SW_UNKNOWN);
outputBuffer[effectiveLen] = msg;
++effectiveLen;
}
and think about RAM vs EEPROM storing of both outputBuffer and effectiveLen.

can not make xpath with functions work with JDOM2

I used JDOM1 before to parse xmls with xpath, and tired with the non-generic style, so I decide to try JDOM2, OK, everything works perfect for me ( the generic, XPathFactory, XPathExpression). then I try a xpath statement with contains function :
XPathExpression<Text> timeXpath = XPathFactory.instance().compile(
"./p[contains(.,'time:')]/text()", Filters.textOnly());
String time = timeXpath.evaluateFirst(div).getTextTrim();
then I got exeptions:
java.lang.IllegalStateException: Unable to evaluate expression. See cause
at org.jdom2.xpath.jaxen.JaxenCompiled.evaluateRawFirst(JaxenCompiled.java:200)
at org.jdom2.xpath.util.AbstractXPathCompiled.evaluateFirst(AbstractXPathCompiled.java:327)
at peace.org.tm.spider.star.DamaiStarSpider.syncStarTracks(DamaiStarSpider.java:123)
at peace.org.tm.spider.star.DamaiStarSpider.main(DamaiStarSpider.java:156)
Caused by: org.jaxen.UnresolvableException: Function :contains
at org.jaxen.SimpleFunctionContext.getFunction(SimpleFunctionContext.java:142)
at org.jaxen.ContextSupport.getFunction(ContextSupport.java:189)
at org.jaxen.Context.getFunction(Context.java:153)
at org.jaxen.expr.DefaultFunctionCallExpr.evaluate(DefaultFunctionCallExpr.java:183)
at org.jaxen.expr.DefaultPredicate.evaluate(DefaultPredicate.java:106)
at org.jaxen.expr.PredicateSet.evaluatePredicates(PredicateSet.java:188)
at org.jaxen.expr.DefaultLocationPath.evaluate(DefaultLocationPath.java:218)
then I tried:
XPathExpression<Text> timeXpath = XPathFactory.instance().compile(
"./p[fn:contains(.,'time:')]/text()", Filters.textOnly());
String time = timeXpath.evaluateFirst(div).getTextTrim();
xpath compile failed:
java.lang.IllegalArgumentException: Unable to compile './p[fn:contains(.,'time:')]/text()'. See Cause.
at org.jdom2.xpath.jaxen.JaxenCompiled.<init>(JaxenCompiled.java:152)
at org.jdom2.xpath.jaxen.JaxenXPathFactory.compile(JaxenXPathFactory.java:82)
at org.jdom2.xpath.XPathFactory.compile(XPathFactory.java:282)
at peace.org.tm.spider.star.DamaiStarSpider.syncStarTracks(DamaiStarSpider.java:91)
at peace.org.tm.spider.star.DamaiStarSpider.main(DamaiStarSpider.java:156)
Caused by: org.jaxen.XPathSyntaxException: Unexpected '('
at org.jaxen.BaseXPath.<init>(BaseXPath.java:136)
at org.jaxen.BaseXPath.<init>(BaseXPath.java:157)
at org.jdom2.xpath.jaxen.JaxenCompiled.<init>(JaxenCompiled.java:150)
... 4 more
I already google the stack trace for about 2 hours, nothing useful founded, I think maybe I made a very stupid mistake, is anyone can figure it out for me? thanks!
I can't reproduce the exceptions you are getting.... I am using JDOM 2.0.5 with Jaxen 1.1.6.
I have created the following:
public static void main(String[] args) {
Element root = new Element ("root");
Element p = new Element("p");
p.addContent(" Return this time: Boo! ");
root.addContent(p);
XPathExpression<Text> timeXpath = XPathFactory.instance().compile(
"./p[contains(.,'time:')]/text()", Filters.textOnly());
XPathDiagnostic<Text> xpd = timeXpath.diagnose(root, true);
System.out.println(xpd);
System.out.println(timeXpath.evaluateFirst(root).getTextTrim());
}
and it produces:
[XPathDiagnostic: './p[contains(.,'time:')]/text()' evaluated (first) against org.jdom2.Element produced raw=1 discarded=0 returned=1]
Return this time: Boo!
I believe you may have out-of-date Jaxen class libraries?

Resources