Home > other >  Variations of creating spring bean dependant on each file exists
Variations of creating spring bean dependant on each file exists

Time:02-15

I have 'reporting' service, that requires input meta data, this metadata are loaded either from metadata.xml or metadata.properties.

Now, the input stream from these files is created as spring bean and autowired in the server. However, if user does not provide metadata file, the service does not report anything, if the user provides only 1 file, it takes data from that file, if the user provides both files, inner logic of service will decide which one it takes ( not important for my question ).

So far i am creating the input streams this way:

@Bean(name = "xml_bean")
@ConditionalOnResource(resources = "classpath:metadata.xml")
@XmlFile
publihgc InputStream getXmlFileInputStream() {
    return getClass().getClassLoader().getResourceAsStream(XML_FILE_NAME);
}

@Bean
@XmlFile
@ConditionalOnMissingBean(name = "xml_bean")
public InputStream getXmlFileDefault() {
    //empty input stream
    return new InputStream() {
        @Override
        public int read() {
            return 0;
        }
    };
}

@Bean(name = "properties_bean")
@ConditionalOnResource(resources = "classpath:metadata.properties")
@PropertyFile
public InputStream getPropertiesFileInputStream() {
    return getClass().getClassLoader().getResourceAsStream(PROPERTIES_FILE_NAME);
}

@Bean
@PropertyFile
@ConditionalOnMissingBean(name = "properties_bean")
public InputStream getPropertiesFileInputStreamDefault() {
    //empty input stream
    return new InputStream() {
        @Override
        public int read() {
            return 0;
        }
    };
}

Spring checks if the file exists, if yes creates input stream bean, otherwise creates empty stream bean.

Now the service, as i said i have 4 cases:

  1. Both files are defined
  2. No file is defined
  3. XML file is defined only
  4. Properties file is defined only

These are 4 cases, as so far i have created 4 conditional beans:

1)Both files are defined:

@Bean("reportingService")
@ConditionalOnBean(name = {"xml_bean", "properties_bean"})
public ReportingService reportingService(@XmlFille final InputStream xmlFileInputStream,
                                     @PropertyFile final InputStream propertiesFileInputStream) {
    return new CachedReportingService (xmlFileInputStream, propertiesFileInputStream);
}

No file defined

@Bean
@ConditionalOnMissingBean(ReportingService.class)
public ReportingService reportingServiceDefault() {
    return new NoOpReportingService ();
}

Only xml file defined

@Bean
@ConditionalOnBean(name = {"xml_bean"})
@ConditionalOnMissingBean(name = "reportingService")
public ReportingService reportingServiceXML (@XmlFile final InputStream xmlFileInputStream) {
    return new CachedReportingService (xmlFileInputStream, null);
}

Only properties file is defined

@Bean
@ConditionalOnBean(name = {"bter_prop_bean"})
@ConditionalOnMissingBean(name = "reportingService")
public ReportingService reportingServiceProperties(
        @BterProperties final InputStream propertiesFileInputStream) {
    return new CachedReportingService (null, propertiesFileInputStream);
} 

Now this works, however for each case i need to create another bean definition. If i had 3 files like this, the cases would jump from 4 to 8. Isnt there better way how to do it?

When i tried to to something like:

@Bean(name = "xml_bean")
@XmlFile
publihgc InputStream getXmlFileInputStream() {
    return getClass().getClassLoader().getResourceAsStream(XML_FILE_NAME);
}    

@Bean
public ReportingService reportingService(@XmlFille final InputStream xmlFileInputStream,
                                     @PropertyFile final InputStream propertiesFileInputStream) {
    return new CachedReportingService (xmlFileInputStream, propertiesFileInputStream);
}

but this will fail, as if when the xml_bean does not have file, classLoader results in null, and that throws error, cuz @XmlFille final InputStream xmlFileInputStream, does not have candidate for autowiring.

Is there any trick to creating beans like this? The way i used seems pretty redundant and complicated

CodePudding user response:

You can do all of that in 1 single method. You can make those InputStream arguments Optional and check what is available, based on that return either a CachedReportingService or NoOpReportingService.

@Bean
public ReportingService reportingService(@XmlFille Optional<InputStream> xmlFileInputStream,
                                     @PropertyFile Optional<InputStream> propertiesFileInputStream) {
  if (xmlFileInputStream.isPresent() || propertiesFileInputStream.isPresent()) {
    return new CachedReportingService(xmlFileInputStream.orElse(null), propertiesFileInputStream.orElse(null));
  } else {
    return new NoOpReportingService();
  }
}

Something like that. Not everything needs to be solved with annotations, you have Java at your fingertips, use it to your advantage.

  • Related