SpringBoot: EL1003E property values casting - spring

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.

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.

How do you define a Duration object in Micronaut's application YAML

I'm trying to define a caffiene cache in micronaut and set the expire time via the application yaml.
The documentation indicates that
micronaut.caches.discovery-client.expire-after-write should be defined as a Duration object but it's unclear how to do so in YAML.
---
micronaut:
application:
name: example-service
caches:
example-cache:
expire-after-write: 86400
Gives the following error:
Internal Server Error: Failed to inject value for parameter [expireAfterWrite] of method [setExpireAfterWrite] of class: io.micronaut.cache.caffeine.DefaultCacheConfiguration
Message: Error resolving property value [micronaut.caches.example-cache.expire-after-write]. Property doesn't exist
Path Taken: new $ExampleControllerDefinition$Intercepted(BeanContext beanContext,Qualifier qualifier,[Interceptor[] interceptors]) --> new CacheInterceptor([CacheManager cacheManager],CacheErrorHandler errorHandler,AsyncCacheErrorHandler asyncCacheErrorHandler,ExecutorService ioExecutor,BeanContext beanContext) --> new DefaultCacheManager([List caches],Provider dynamicCacheManager) --> new DefaultSyncCache([CacheConfiguration cacheConfiguration],ApplicationContext applicationContext,ConversionService conversionService) --> DefaultCacheConfiguration.setExpireAfterWrite([Duration expireAfterWrite])
io.micronaut.http.client.exceptions.HttpClientResponseException: Internal Server Error: Failed to inject value for parameter [expireAfterWrite] of method [setExpireAfterWrite] of class: io.micronaut.cache.caffeine.DefaultCacheConfiguration
Presumably as the value is being treated as an Integer not a Duration
It appears you can do it as simply as this:
---
micronaut:
application:
name: example-service
caches:
example-cache:
expire-after-write: 24h

Java 8 -> Collectors.toMap -> Duplicate key

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);

SpringBoot emoji input

I have a SpringBoot application. On one of the POST endpoints, in the body I want a field that can contain emoji.
In my request object I have the following field:
private final String name;
In the body of my request I have the following input:
"name" : "Hello, playground \Ud83d\Ude0a \Ud83e\Udd21\Ud83d\Udc68\U200d\Ud83c\Udf73 \U2663\Ufe0f"
which contains some emojis.
The exception I get is:
com.fasterxml.jackson.databind.JsonMappingException: Unrecognized character escape 'U' (code 85)
and
Caused by: com.fasterxml.jackson.core.JsonParseException: Unrecognized character escape 'U' (code 85)
I tried to set the following flag on my object mapper with no luck:
.configure(JsonParser.Feature.ALLOW_BACKSLASH_ESCAPING_ANY_CHARACTER, true)
Any ideas?

jdbcType=BIGDECIMAL not supported in mybatis and ibatis

Using jdbcType=BIGDECIMAL is not supported in myBatis and ibatis and is throwing the next error:
Error resolving JdbcType. Cause: java.lang.IllegalArgumentException:
No enum constant org.apache.ibatis.type.JdbcType.BIGDECIMAL
What is the jdbcType alternative instead of BIGDECIMAL?
I'm using mybatis-3.4.4 version
That's happen because BIGDECIMAL jdbc type doesn't exist. Just take a look the enum JdbcType of org.apache.ibatis.type.
You should use DECIMAL.
The list of JdbcTypes available in JdbcType enum:
ARRAY(2003),
BIT(-7),
TINYINT(-6),
SMALLINT(5),
INTEGER(4),
BIGINT(-5),
FLOAT(6),
REAL(7),
DOUBLE(8),
NUMERIC(2),
DECIMAL(3),
CHAR(1),
VARCHAR(12),
LONGVARCHAR(-1),
DATE(91),
TIME(92),
TIMESTAMP(93),
BINARY(-2),
VARBINARY(-3),
LONGVARBINARY(-4),
NULL(0),
OTHER(1111),
BLOB(2004),
CLOB(2005),
BOOLEAN(16),
CURSOR(-10),
UNDEFINED(-2147482648),
NVARCHAR(-9),
NCHAR(-15),
NCLOB(2011),
STRUCT(2002),
JAVA_OBJECT(2000),
DISTINCT(2001),
REF(2006),
DATALINK(70),
ROWID(-8),
LONGNVARCHAR(-16),
SQLXML(2009),
DATETIMEOFFSET(-155);
By using below type handler I have resolved my same issue:
<insert id=".......">
INSERT INTO demo (number_of_cities)
VALUES( #{numberOfCities, typeHandler=org.apache.ibatis.type.BigDecimalTypeHandler});
</insert>

Resources