Drive V3 API : java.lang.IllegalArgumentException - google-api

This is how I create "AbstractInputStreamContent" from inputstream of file:
final Long length = Long.valueOf(filesData.get(uploadedFileName).get("size")).longValue();
final InputStream fileStream = item.openStream(); //FileItemStream item
AbstractInputStreamContent fileContent = new AbstractInputStreamContent(uploadedFileMimeType) {
#Override
public boolean retrySupported() {
return false;
}
#Override
public long getLength() throws IOException {
return length;
}
#Override
public InputStream getInputStream() throws IOException {
return fileStream;
}
};
And "InputStreamContent" as:
InputStreamContent fileContent = new InputStreamContent(uploadedFileMimeType, item.openStream());
fileContent.setLength(Long.valueOf(filesData.get(uploadedFileName).get("size")).longValue());
To replace old file with new file I use(both files are of .docx format):
Drive.Files.Update update = driveService.files().update(fileIdOfFileToReplace,fileMeta,fileContent);
update.set("uploadType", "resumable");
update.getMediaHttpUploader().setDirectUploadEnabled(false);
update.getMediaHttpUploader().setChunkSize(MediaHttpUploader.DEFAULT_CHUNK_SIZE);
File updatedFile = update.execute();
Uploading a new file works fine whether I use InputStreamContent or AbstractInputStreamContent. But update gives "java.lang.IllegalArgumentException" with both
java.lang.IllegalArgumentException
at com.google.api.client.repackaged.com.google.common.base.Preconditions.checkArgument(Preconditions.java:111)
at com.google.api.client.util.Preconditions.checkArgument(Preconditions.java:37)
at com.google.api.client.googleapis.media.MediaHttpUploader.setInitiationRequestMethod(MediaHttpUploader.java:872)
at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.initializeMediaUpload(AbstractGoogleClientRequest.java:237)
at com.google.api.services.drive.Drive$Files$Update.<init>(Drive.java:3163)
at com.google.api.services.drive.Drive$Files.update(Drive.java:3113)
at com.util.DocumentsUtil.updateFile(DocumentsUtil.java:22)
at com.controllers.collab.documents.Documents.fileUpload(Documents.java:165)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:44)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:221)
at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:136)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:110)

Solved it by giving exclusion of google-api-client from each google api maven dependency. Later added google-api-client-1.22.0-SNAPSHOT dependency from sonatype repo. It works fine

Related

How to resolve ClassCastException in MultiResourceItemReader Spring Batch

I'm reading multiple files from the S3 bucket using MultiResourceItemReader, I'm getting ClassCastException before executing the myReader() method, Something wrong with MultiResourceItemReader not sure what's going wrong here.
Please find my code below:
#Bean
public MultiResourceItemReader<String> multiResourceReader()
{
String bucket = "mybucket;
String key = "/myfiles";
List<InputStream> resourceList = s3Client.getFiles(bucket, key);
List<InputStreamResource> inputStreamResourceList = new ArrayList<>();
for (InputStream s: resourceList) {
inputStreamResourceList.add(new InputStreamResource(s));
}
Resource[] resources = inputStreamResourceList.toArray(new InputStreamResource[inputStreamResourceList.size()]);
//InputStreamResource[] resources = inputStreamResourceList.toArray(new InputStreamResource[inputStreamResourceList.size()]);
// I'm getting all the stream content - I verified my stream is not null
for (int i = 0; i < resources.length; i++) {
try {
InputStream s = resources[i].getInputStream();
String result = IOUtils.toString(s, StandardCharsets.UTF_8);
System.out.println(result);
} catch (IOException e) {
e.printStackTrace();
}
}
MultiResourceItemReader<String> resourceItemReader = new MultiResourceItemReader<>();
resourceItemReader.setResources(resources);
resourceItemReader.setDelegate(myReader());
resourceItemReader.setDelegate((ResourceAwareItemReaderItemStream<? extends String>) new CustomComparator());
return resourceItemReader;
}
Exception:
Caused by: java.lang.ClassCastException: class CustomComparator cannot be cast to class org.springframework.batch.item.file.ResourceAwareItemReaderItemStream (CustomComparator and org.springframework.batch.item.file.ResourceAwareItemReaderItemStream are in unnamed module of loader org.springframework.boot.loader.LaunchedURLClassLoader #cc285f4)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:244)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:331)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:566)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:154)
... 65 common frames omitted
Can someone please help me to resolve this issue. Appreciated your help in advance. Thanks.
The reason you see the NullPointerException is due to the default comparator used by the MultiResourceItemReader to sort the resources after loading them.
The default compare behavior calls the getFilename() method of the InputStreamResource.
Refer - https://github.com/spring-projects/spring-batch/blob/115c3022147692155d45e23cdd5cef84895bf9f5/spring-batch-infrastructure/src/main/java/org/springframework/batch/item/file/MultiResourceItemReader.java#L82
But the InputStreamResource just inherits the getFileName() method from its parent AbstractResource, which just returns null.
https://github.com/spring-projects/spring-framework/blob/316e84f04f3dbec3ea5ab8563cc920fb21f49749/spring-core/src/main/java/org/springframework/core/io/AbstractResource.java#L220
The solution is to provide a custom comparator for the MultiResourceItemReader. Here is a simple example, assuming you do not want to sort the resources in a specific way before processing:
public class CustomComparator implements Comparator<InputStream>{
#Override
public int compare(InputStream is1, InputStream is2) {
//comparing based on last modified time
return Long.compare(is1.hashCode(),is2.hashCode());
}
}
MultiResourceItemReader<String> resourceItemReader = new MultiResourceItemReader<>();
resourceItemReader.setResources(resources);
resourceItemReader.setDelegate(myReader());
//UPDATED with correction - set custom Comparator
resourceItemReader.setComparator(new CustomComparator());
Refer this answer for how a Comparator is used by Spring Batch MultiResourceItemReader.
File processing order with Spring Batch

Converting MultipartFile to File

I am trying to convert a MultipartFile to File but multipartFile.transferTo(uploadedFile); is throwing an IOException.
To me it looks like the application is looking for the uploadedFile at '/tmp/tomcat.8080.434182389216770471/work/Tomcat/localhost/ROOT/upload_43f33560_23be_4189_843c_d9062cb44ec2_00000000.tmp' instead of src/main/resources/targetFile.tmp
#GetMapping("/reportError")
public String error(Model model) throws MessagingException, IOException {
EmailService emailService = new EmailService();
File uploadedFile = new File("src/main/resources/targetFile.tmp");
multipartFile.transferTo(uploadedFile);
emailService.sendmail(Arrays.asList(uploadedFile, dailyReportFile, shiftReportFile));
model.addAttribute("msg", "Thanks for reporting.\nIt helps us improve the app.");
return "messageView";
}
java.io.IOException: java.io.FileNotFoundException:
/tmp/tomcat.8080.434182389216770471/work/Tomcat/localhost/ROOT/upload_43f33560_23be_4189_843c_d9062cb44ec2_00000000.tmp
(No such file or directory) at
org.apache.catalina.core.ApplicationPart.write(ApplicationPart.java:122)
~[tomcat-embed-core-9.0.45.jar:9.0.45] at
org.springframework.web.multipart.support.StandardMultipartHttpServletRequest$StandardMultipartFile.transferTo(StandardMultipartHttpServletRequest.java:256)
~[spring-web-5.3.6.jar:5.3.6] at
gmailgdogra.controller.AppController.error(AppController.java:202)
~[classes/:na] at sun.reflect.NativeMethodAccessorImpl.invoke0(Native
Method) ~[na:1.8.0_292] at
java.lang.Thread.run(Thread.java:748) [na:1.8.0_292] Caused by:
java.io.FileNotFoundException:
/tmp/tomcat.8080.434182389216770471/work/Tomcat/localhost/ROOT/upload_43f33560_23be_4189_843c_d9062cb44ec2_00000000.tmp
(No such file or directory) at java.io.FileInputStream.open0(Native
Method) ~[na:1.8.0_292] at
java.io.FileInputStream.open(FileInputStream.java:195) ~[na:1.8.0_292]
at java.io.FileInputStream.(FileInputStream.java:138)
~[na:1.8.0_292] at
org.apache.tomcat.util.http.fileupload.disk.DiskFileItem.write(DiskFileItem.java:404)
~[tomcat-embed-core-9.0.45.jar:9.0.45] at
org.apache.catalina.core.ApplicationPart.write(ApplicationPart.java:120)
~[tomcat-embed-core-9.0.45.jar:9.0.45] ... 52 common frames omitted
And my Test pass with similar code
#Test
void convert() throws IOException {
MultipartFile multipartFile = new MockMultipartFile("sourceFile.tmp", "Hello World".getBytes());
File file = new File("src/main/resources/targetFile.tmp");
multipartFile.transferTo(file);
assertThat(FileUtils.readFileToString(new File("src/main/resources/targetFile.tmp"), "UTF-8"))
.isEqualTo("Hello World");
}
Below code works well if I don't send the converted Multipart file.
#GetMapping("/reportError")
public String error(Model model) throws MessagingException, IOException {
EmailService emailService = new EmailService();
emailService.sendmail(Arrays.asList(dailyReportFile, shiftReportFile));
model.addAttribute("msg", "Thanks for reporting.\nIt helps us improve the app.");
return "messageView";
}
#GetMapping("/reportError")
public String error(Model model) throws MessagingException, IOException {
InputStream initialStream = multipartFile.getInputStream();
byte[] buffer = new byte[initialStream.available()];
initialStream.read(buffer);
File targetFile = new File("src/main/resources/targetFile.tmp");
try (OutputStream outStream = new FileOutputStream(targetFile)) {
outStream.write(buffer);
}
EmailService emailService = new EmailService();
emailService.sendmail(Arrays.asList(targetFile, dailyReportFile, shiftReportFile));
model.addAttribute("msg", "Thanks for reporting.\nIt helps us improve the app.");
return "messageView";
}
I have tried above but it fails with message
java.io.FileNotFoundException:
/tmp/tomcat.8080.486619881437185002/work/Tomcat/localhost/ROOT/upload_43ba6a8d_27c9_49de_a73e_4f9026fc852e_00000000.tmp
(No such file or directory) at java.io.FileInputStream.open0(Native
Method) ~[na:1.8.0_292] at
java.io.FileInputStream.open(FileInputStream.java:195) ~[na:1.8.0_292]
at java.io.FileInputStream.(FileInputStream.java:138)
~[na:1.8.0_292] at
org.apache.tomcat.util.http.fileupload.disk.DiskFileItem.getInputStream(DiskFileItem.java:194)
~[tomcat-embed-core-9.0.45.jar:9.0.45] at
org.apache.catalina.core.ApplicationPart.getInputStream(ApplicationPart.java:100)
~[tomcat-embed-core-9.0.45.jar:9.0.45] at
Edit
Similar problem similar stackoverflow question. But none of the provided solution has worked for me.
Tried below code but it also failed
#GetMapping("/reportError")
public String error(Model model) throws MessagingException, IOException {
EmailService emailService = new EmailService();
File uploadedFile = convert(multipartFile);
System.out.println("transferTo completed");
emailService.sendmail(Arrays.asList(uploadedFile, dailyReportFile, shiftReportFile));
model.addAttribute("msg", "Thanks for reporting.\nIt helps us improve the app.");
return "messageView";
}
public File convert(MultipartFile file) throws IOException {
File convFile = new File(file.getOriginalFilename());
convFile.createNewFile();
FileOutputStream fos = new FileOutputStream(convFile);
fos.write(file.getBytes());
fos.close();
return convFile;
}
Thanks

Firebase Admin SDK fials on AWS Elastic Beantalk

I recently deployed a Spring Boot app to Elastic Beanstalk.
Spring starts with no errors.
We are using Firebase for user authentication. On a local machiene or even on other external hosts the Firebase operations worked all fine, but not on EBS.
If i read the logs:
java.lang.IllegalStateException: FirebaseApp with name [DEFAULT] doesn't exist.
at com.google.firebase.FirebaseApp.getInstance(FirebaseApp.java:164) ~[firebase-admin-6.3.0.jar!/:na]
at com.google.firebase.FirebaseApp.getInstance(FirebaseApp.java:135) ~[firebase-admin-6.3.0.jar!/:na]
at com.google.firebase.auth.FirebaseAuth.getInstance(FirebaseAuth.java:100) ~[firebase-admin-6.3.0.jar!/:na]
at com.bodymate.springend.mvc.service.FirebaseService.validateToken(FirebaseService.java:15) ~[classes!/:1.0-SNAPSHOT]
at com.bodymate.springend.mvc.controller.UserController.register(UserController.java:66) ~[classes!/:1.0-SNAPSHOT]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_181]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_181]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_181]
at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_181]...
This is my firebase config:
#Configuration
public class FirebaseConfig {
#PostConstruct
public void init() {
FirebaseOptions options;
try {
FileInputStream serviceAccount = new FileInputStream("src/main/resources/google-services.json");
options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.build();
} catch (java.io.IOException e) {
e.printStackTrace();
return;
}
FirebaseApp.initializeApp(options);
}
}
The point where it gets out of hand:
#Service
public class FirebaseService {
public FirebaseToken validateToken(String token) throws InterruptedException, ExecutionException, InvalidFirebaseTokenException {
FirebaseToken decodedToken = FirebaseAuth.getInstance().verifyIdTokenAsync(token).get();
if( decodedToken != null && decodedToken.getUid() != null && !decodedToken.getUid().isEmpty()){
return decodedToken;
}else{
throw new InvalidFirebaseTokenException();
}
}
}
Does someone has any idea what is going wrong here ?
EDIT
I am using mvn clean install to build my .jar file for EBS.
Is it possible that this build does not contain the "google-services.json" ?

AuthenticationFailedException: AUTHENTICATE failed After some connections

I have a Spring-Boot (1.4.0) application and I am using springframework.boot:spring-boot-starter-mail.
I have a method annotated with #Scheduled to check my inbox every a certain period of time.
This is how I get my inbox:
private static Folder getInbox() throws MessagingException {
final String protocol = "mail.store.protocol";
final String storeType = "imaps";
final String email = "email";
final String password = "password";
final String connect = "webmail.company.com";
final String folder = "INBOX";
final Properties props = new Properties();
props.setProperty(protocol, storeType);
final Session session = Session.getInstance(props, null);
final Store store = session.getStore();
store.connect(connect, email, password);
final Folder inbox = store.getFolder(folder);
inbox.open(Folder.READ_WRITE);
return inbox;
}
Then I have this:
#Scheduled(fixedRate = 10000)
#Override
public void checkEmailCreateCompanyAndSendCsv() throws MessagingException, IOException {
log.info("Checking e-mail...");
final Folder inbox = getInbox();
final Flags seen = new Flags(Flags.Flag.SEEN);
final FlagTerm unseenFlagTerm = new FlagTerm(seen, false);
inbox.getMessages();
final Message messages[] = inbox.search(unseenFlagTerm);
.....
.....
}
When the APP is running everything works great but after some time (around 7 to 8 e-mail checks) it starts to thrown an exception:
javax.mail.AuthenticationFailedException: AUTHENTICATE failed. at
com.sun.mail.imap.IMAPStore.protocolConnect(IMAPStore.java:717) at
javax.mail.Service.connect(Service.java:366) at
javax.mail.Service.connect(Service.java:246) at
com.opessoftware.crs.selfcertification.services.EmailServiceBasic.getInbox(EmailServiceBasic.java:183)
at
com.opessoftware.crs.selfcertification.services.EmailServiceBasic.checkEmailCreateCompanyAndSendCsv(EmailServiceBasic.java:50)
at sun.reflect.GeneratedMethodAccessor28.invoke(Unknown Source) at
sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498) at
org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65)
at
org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at
java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
at
java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
at
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
If I stop the application and run it again the error disappears and the cicle starts again.
Any suggestions?
I just solved it.
I was calling the connection too many times and I was exceeding the connection pool of my e-mail server. So what I did is to define the getInbox() and the getSession() as #Bean and Inject them to my EmailService.
Now it creates the connection only once. It is working fine.

Exception accessing Spring managed bean from Groovy closure

I have a simple Spring Boot application with 2 bean classes, a main class and a configuration class. Whenever I try to access the Spring managed Bank bean from a Groovy closure, I get an exception:
Exception in thread "main" java.lang.IllegalStateException: Failed to execute CommandLineRunner
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:304)
at org.springframework.boot.SpringApplication.runCommandLineRunners(SpringApplication.java:675)
at com.example.closures.ClosuresApplication$_run_closure1.doCall(ClosuresApplication.groovy:22)
at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:690)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:321)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:957)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:946)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.boot.SpringApplication$run.call(Unknown Source)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at groovy.lang.MetaMethod.doMethodInvoke(MetaMethod.java:324)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:110)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:130)
at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod(ClosureMetaClass.java:292)
at com.example.closures.ClosuresApplication.main(ClosuresApplication.groovy:27)
at groovy.lang.MetaClassImpl.invokeMethod(MetaClassImpl.java:1016)
Caused by: groovy.lang.MissingPropertyException: No such property: bank for class: com.example.closures.ClosuresApplication$$EnhancerBySpringCGLIB$$44735576
at groovy.lang.Closure.call(Closure.java:423)
at groovy.lang.Closure.call(Closure.java:439)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2027)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:51)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2012)
at org.codehaus.groovy.runtime.callsite.PogoGetPropertySite.getProperty(PogoGetPropertySite.java:49)
at org.codehaus.groovy.runtime.DefaultGroovyMethods.each(DefaultGroovyMethods.java:2053)
at org.codehaus.groovy.runtime.dgm$162.invoke(Unknown Source)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callGroovyObjectGetProperty(AbstractCallSite.java:304)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite$PojoMetaMethodSiteNoUnwrapNoCoerce.invoke(PojoMetaMethodSite.java:271)
at org.codehaus.groovy.runtime.callsite.PojoMetaMethodSite.call(PojoMetaMethodSite.java:53)
at com.example.closures.ClosuresApplication$_run_closure1.doCall(ClosuresApplication.groovy:22)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:45)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:110)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:122)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.example.closures.ClosuresApplication.run(ClosuresApplication.groovy:21)
at org.codehaus.groovy.reflection.CachedMethod.invoke(CachedMethod.java:90)
at org.springframework.boot.SpringApplication.runCommandLineRunners(SpringApplication.java:672)
... 9 common frames omitted
Bank.groovy
#Component
final class Bank {
final String name = 'MyBank'
final AutomatedTellerMachine insideAtm
final AutomatedTellerMachine outsideAtm
#Autowired
Bank(#Qualifier('insideAtm') final AutomatedTellerMachine insideAtm, #Qualifier('outsideAtm') final AutomatedTellerMachine outsideAtm) {
this.insideAtm = insideAtm
this.outsideAtm = outsideAtm
}
String getName() {
return name
}
AutomatedTellerMachine getInsideAtm() {
return insideAtm
}
AutomatedTellerMachine getOutsideAtm() {
return outsideAtm
}
}
AutomatedTellerMachine.groovy
final class AutomatedTellerMachine {
final String name
AutomatedTellerMachine(final String name) {
this.name = name
}
String getName() {
return name
}
}
AppConfig.groovy
#Configuration
class AppConfig {
#Bean(name = 'insideAtm')
AutomatedTellerMachine getInsideAtm() {
new AutomatedTellerMachine('insideAtm')
}
#Bean(name = 'outsideAtm')
AutomatedTellerMachine getOutsideAtm() {
new AutomatedTellerMachine('outsideAtm')
}
}
ClosuresApplication.groovy
#SpringBootApplication
class ClosuresApplication implements CommandLineRunner {
#Autowired
private Bank bank
#Override
void run(String... args) throws Exception {
for (def i = 0; i < 10; i++) {
printf 'Bank %02d: %s%n', (i + 1), bank
}
(1..10).each {
printf 'Bank %02d: %s%n', it, bank
}
}
static void main(String[] args) {
SpringApplication.run ClosuresApplication, args
}
}
The regular for loop works just fine, but the .each {} closure from Groovy gives an exception. Any ideas?
I have run into this problem at odd times and found that a simple work-around can fix it - add a reference to your bank variable in the run method:
def _bank = bank
(1..10).each {
printf 'Bank %02d: %s%n', it, _bank
}
It seems to be an odd scoping issue that I have never been able to determine the real cause of.
Another possible solution is converting bank field to groovy property by removing 'private' modifier.
#Autowired
Bank bank
This is slightly less visually hideous (especially if you having this issue with more than one field), but it does change access level of that field.
I've encountered a number of these issues, all seemingly related to using private fields inside various closures in spring-managed beans, specifically when the beans are 'enhanced' (proxied) by spring (EnhancerBySpringCGLIB).

Resources