Hi Alain, Since you are annotating classes that are generated, does the generator has some configurability? Is it possible for you to instead generate configurations? The config could be a properties file, a JSON, or even a class if necessary.
If this is possible, you could for instance use the extender pattern to instantiate the services for you, rather than trying to manually build a single component for each generated file. Generate the configurations, export them to a known folder in a bundle, and when the bundle is deployed, read the configs and instantiate the services. Right now, it sounds like you are making yourself an extension to the generator. If you can reduce the manual work by capturing only what varies and automating the repetition, perhaps that would be a more elegant solution. One service per generated “class” sounds right to me, but IMO there seems to be a bit of a smell to the manual additions to each generated file. Think of it from the perspective of your builds. Every time you build a new system, you’ll have to do manual work to construct your components. Would be better to have an end-to-end build that does not require manual intervention. Don’t you think? In case you did not now (it was not obvious to me before I first discovered it) you can also configure the @References with a “xxx.target” configuration property. DS should give you all you need to configure your services. Now I’m very curious, so please let me know how you end up solving this. :-) Cheers, =David > On Aug 12, 2018, at 22:00, Alain Picard <pic...@castortech.com> wrote: > > Just realized that I could have applied the same pattern to the BaseMapData > and not use the implementation class there either. > > Alain > > On Sun, Aug 12, 2018 at 8:58 AM Alain Picard <pic...@castortech.com > <mailto:pic...@castortech.com>> wrote: > To David, > > Your comment got me thinking some more about this. And given that I have > about 25 different variations and each has 3 variants, that would mean > introducing somewhere like 75 "marker" interfaces. > > Here's what I did: > > A number of key classes are generated and sometimes partly modified by hand. > So in the "main" such class I have: > /** > * This class is generated by Iris-Mapping. > * > * @generated > */ > @Component( > property = { > IBaseMapData.CONFIG_MAPPING_ID + "=" + > "com.castortech.iris.mapping.project.baModel.asset", > IBaseMapData.CONFIG_MAPPING_NAME + "=" + > BaModelAssetMapData.TABLE_NAME, > IBaseMapData.CONFIG_MAPPING_XL_READER + "=" + > "com.castortech.iris.mapping.maps.project.baModel.asset.BaModelAssetXlReader", > IBaseMapData.CONFIG_MAPPING_XL_WRITER + "=" + > "com.castortech.iris.mapping.maps.project.baModel.asset.BaModelAssetXlWriter" > }, > service=BaModelAssetMapData.class > ) > public final class BaModelAssetMapData extends > BaseMapData<BaModelAssetMapTable, BaModelAssetMapRecord> { > public static final String TABLE_NAME = "Asset"; //$NON-NLS-1$ > public static final String PROP_TABLE_NAME = > MappingConstants.CONFIG_TABLE_NAME + "=" + TABLE_NAME; //$NON-NLS-1$ > public static final String TARGET_TABLE_NAME = "(" + > MappingConstants.CONFIG_TABLE_NAME + "=" + TABLE_NAME + ")"; //$NON-NLS-1$ > //$NON-NLS-2$ //$NON-NLS-3$ > ... > > and then I will have: > @Component(property=BaModelAssetMapData.PROP_TABLE_NAME) > public final class AssetXlExporter implements BaXlExportContent { > @Reference > private BaXlExportUtils<BaModelAssetXlWriter, BaModelAssetMapTable, > BaModelAssetMapRecord> exporter; > > @Reference(target=BaModelAssetMapData.TARGET_TABLE_NAME) > private ExportTable<BaModelAssetMapTable> exportTable; > > and in another location where the exporter is used as a reference: > .... > @Reference(target=BaModelAssetMapData.TARGET_TABLE_NAME) > private AssetXlExporter assetXlExporter; > ... > > To me this avoids the previous issue of exposing the implementation class and > using generated constants, allows to have readable code where annotations > don't become unreadable. > > Does it make sense? > > Alain > > On Sun, Aug 12, 2018 at 8:22 AM David Leangen <o...@leangen.net > <mailto:o...@leangen.net>> wrote: > > Hi Alain, > > Maybe there is a way of having 25 different interfaces in your API instead? > > Or, if they are private, maybe you don’t even need to use services? > > Are you able to share your code? Would be helpful to have a little more > information. > > > Cheers, > =David > > > >> On Aug 12, 2018, at 6:58, Alain Picard <pic...@castortech.com >> <mailto:pic...@castortech.com>> wrote: >> >> On Sat, Aug 11, 2018 at 4:10 PM David Leangen <o...@leangen.net >> <mailto:o...@leangen.net>> wrote: >> >> Hi Alain, >> >> What is it you are trying to accomplish? Is there a reason you are exposing >> the implementation class? >> >> Maybe you know this already, but the “usual” practice is to expose an >> interface in your API (and export the containing package), and to keep the >> implementation private. >> Yes, absolutely, and that's why I'm asking. I have about 25 different >> implementation of the interfaces that are most often referenced directly >> from a matching component (i.e. for the same table) and a few cases where >> they are invoked generically. Here all of those are in a single bundle so >> this is more like a "private" API and the use of a class is not a real >> problem. But I didn't feel like using @Reference(target=(tableName=x) for >> each case. Hence my question. >> >> Alain >> >> Also: >> >> > Collection<ServiceReference<T>> servRefs = >> > bcontext.getServiceReferences(target, props.get("filter")); //filter to >> > be like: "(target >> > servRef = servRefs.isEmpty() ? null : servRefs.iterator().next(); >> >> Did some text get cut out of your post? >> >> If you can explain a little more what you are trying to do I think that >> would be helpful. >> >> >> Cheers, >> =David >> >> >> > On Aug 12, 2018, at 1:27, Alain Picard via osgi-dev >> > <osgi-dev@mail.osgi.org <mailto:osgi-dev@mail.osgi.org>> wrote: >> > >> > Looking for confirmation or insight in how best to specify components and >> > references, so that the same component can be invoked directly or more >> > generically through its interface. >> > >> > Let's say that I have some components, 1 per table to do some export >> > function: >> > >> > @Component( >> > property= MappingConstants.CONFIG_TABLE_NAME + "=BigTable", >> > service= { BigTableXlExporter.class, XlExportContent.class } >> > ) >> > public final class BigTableXlExporter implements XlExportContent {...} >> > >> > and in another component I can get a specific reference with: >> > @Component(service=SomeComp.class) >> > public final class SomeComp >> > @Reference >> > private BigTableXlExporter exporter; >> > ... >> > } >> > >> > and in another case i could get a more generic invocation (as part of >> > config or through a factory: >> > @Component(service=GenericComp.class) >> > public final class GenericComp >> > @Activate >> > private void init(Map<String,Object> props, BundleContext bcontext) { >> > ServiceReference servRef; >> > try { >> > Collection<ServiceReference<T>> servRefs = >> > bcontext.getServiceReferences(target, props.get("filter")); //filter to >> > be like: "(target >> > servRef = servRefs.isEmpty() ? null : servRefs.iterator().next(); >> > } >> > catch (InvalidSyntaxException e) { >> > throw new IllegalArgumentException("Invalid Filter Syntax >> > Exception", e); >> > } >> > >> > //do something with ref.... >> > } >> > } >> > >> > Does this make sense or are there better ways to do this. >> > >> > Alain >> > >> > _______________________________________________ >> > OSGi Developer Mail List >> > osgi-dev@mail.osgi.org <mailto:osgi-dev@mail.osgi.org> >> > https://mail.osgi.org/mailman/listinfo/osgi-dev >> > <https://mail.osgi.org/mailman/listinfo/osgi-dev> >> >
_______________________________________________ OSGi Developer Mail List osgi-dev@mail.osgi.org https://mail.osgi.org/mailman/listinfo/osgi-dev