Hi,

I'd like feedback on a design choice. 

The current implementation of dynamic services uses annotations, but I'm
doing some iteration on the design and came up with this alternative idea
that might be cleaner.



ALTERNATIVE #1

DynamicService (which is returned in a collection by a
@DynamicServiceContributor method in the module) is defined as follows:

public interface DynamicService {
    Set<Annotation> getAnnotations();
}

The idea is that a DynamicService also implements a build(...) method,
which can be buildASDFASDF(...) or @Annotations build(...) and the
getAnnotations method allows adding dynamic annotations, like Markers or
the service id. The service interface is derived from the return type of
the build(...) method.

A downside to this is that you need to construct Annotation objects. For
this I could add a new service in IoC (and in fact, the tip of my git repo
points to a commit that adds this service), DynamicAnnotationHelper, with
methods createMarkerAnnotation(Class... markers),
createEagerLoadAnnotation(), createScopeAnnotation(String value),
createServiceIdAnnotation(String serviceId),
createPreventMethodDecorationAnnotation(). This service uses the
ClassFactory (javassist) to create Annotation objects, including
hashCode(), toString(), equals() and stuff like that. It's quite complex,
but I got something that works and even a couple of test cases, comparing
them to ordinary annotations (hashCode(), equals() work as well).

A plus to this is that it's perhaps more dynamic.




ALTERNATIVE #2

public interface DynamicService {
    Set<Class> getMarkers(); // may be null
    String getServiceId(); // required
    String getScope(); // may be null
    boolean getEagerLoad(); // return false by default (could use Boolean
and allow null)
    boolean getPreventServiceDecoration(); // return false by default
(could use Boolean and allow null)
}

Now there also needs to be a build() method of course, but its annotations
are ignored and it shouldn't have a buildASDFASDF() format, because that's
ignored too. The build() method may have any number of (to be injected)
parameters, just like any other build method.

Another alternative is:

public abstract class DynamicService {
    public abstract String getServiceId();
    public Set<Class>getMarkers() { return null; }
    public String getScope() { return null; }
    public boolean getEagerLoad() { return false; }
    public boolean getPreventServiceDecoration() { return false; }
}

Either way, this saves the complexity of creating annotation objects on
the fly (which is complex and doesn't really serve a purpose because they
are only an indirect method of defining markers, service ids, scope, etc,
anyway - there is no real added semantics or expressivity)

The downside is that if there is new functionality (e.g. a new
annotation), the interface must be changed as well, hurting compatibility. 

This can be solved by using an abstract class DynamicService with default
values. If the DynamicService abstract class would be updated with extra
functionality, backward compatibility could be preserved. An alternative to
using abstract classes would be to add new interfaces when new
functionality is added: DynamicService2, DynamicService3, etc just like
with the ModuleDefs.

Another upside of using an abstract class is that not every method needs
to be implemented, only serviceId and build() are really required.





Basically, that lists most of the pros and cons I can come up with right
now. 

So:
#1 = use annotations
#2a = use interface 
#2b = use abstract class 

Considering that we can always create a DynamicService2 interface and
provide toDynamicService2() methods, I'm leaning towards #2a for the
following reasons:
* #1 adds too much unnecessary complexity
* interfaces are preferred above abstract classes (this is just intuition
speaking)

However, #2b also appeals for not requiring every method to be
implemented.

I'm also not sure if it is currently possible to add new
annotations/functionality to the builder methods without modifying the IoC.

Any thoughts?


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to