When using AutoValue with the Builder pattern, how can I initialize other custom final fields in the constructor?
Example
#AutoValue
abstract class PathExample {
static Builder builder() {
return new AutoValue_PathExample.Builder();
}
abstract String directory();
abstract String fileName();
abstract String fileExt();
Path fullPath() {
return Paths.get(directory(), fileName(), fileExt());
}
#AutoValue.Builder
interface Builder {
abstract Builder directory(String s);
abstract Builder fileName(String s);
abstract Builder fileExt(String s);
abstract PathExample build();
}
}
in the real-world class the initialisation (like in the `fullPath field) is more expensive, so that I want to do it only once. I see 2 ways to do this:
1) lazy initialisation
private Path fullPath;
Path getFullPath() {
if (fullPath == null) {
fullPath = Paths.get(directory(), fileName(), fileExt());
}
return fullPath;
}
2) initalisation in the builder
private Path fullPath;
Path getFullPath() {
return fullPath;
}
#AutoValue.Builder
abstract static class Builder {
abstract PathExample autoBuild();
PathExample build() {
PathExample result = autoBuild();
result.fullPath = Paths.get(result.directory(), result.fileName(), result.fileExt());
return result;
}
is there another alternative, so that the fullPath field can be final?
You could simply have a Builder method that takes the full path and use a default value:
#AutoValue
abstract class PathExample {
static Builder builder() {
return new AutoValue_PathExample.Builder();
}
abstract String directory();
abstract String fileName();
abstract String fileExt();
abstract Path fullPath();
#AutoValue.Builder
interface Builder {
abstract Builder directory(String s);
abstract Builder fileName(String s);
abstract Builder fileExt(String s);
abstract Builder fullPath(Path p);
abstract PathExample autoBuild();
public PathExample build() {
fullPath(Paths.get(directory(), fileName(), fileExt()));
return autoBuild();
}
}
}
This should be pretty safe since the constructor will be made private so there should be no situation in which an instance can be created without going through the build() method path unless you create your own static factory methods, in which case you can do the same thing.
Related
Is it possible to use inheritance in Spring Boot YML configuration classes? If so, how would that be accomplished?
For example:
#ConfigurationProperties(prefix="my-config")
public class Config {
List<Vehicle> vehicles;
}
And the class (or interface) "Vehicle" has two implementations: Truck and Car. So the YAML might look like:
my.config.vehicles:
-
type: car
seats: 3
-
type: truck
axles: 3
I do not think it is possible (at least not that I know of). You could however design your code as follow:
Inject the properties into a Builder object
Define an object with all properties, which we'll call the VehicleBuilder (or factory, you choose its name).
The VehicleBuilders are injected from the Yaml.
You can then retrieve each builder's vehicle in a #PostConstruct block. The code:
#ConfigurationProperties(prefix="my-config")
#Component
public class Config {
private List<VehicleBuilder> vehicles = new ArrayList<VehicleBuilder>();
private List<Vehicle> concreteVehicles;
public List<VehicleBuilder> getVehicles() {
return vehicles;
}
public List<Vehicle> getConcreteVehicles() {
return concreteVehicles;
}
#PostConstruct
protected void postConstruct(){
concreteVehicles = vehicles.stream().map(f -> f.get())
.collect(Collectors.<Vehicle>toList());
}
}
The builder:
public class VehicleBuilder {
private String type;
private int seats;
private int axles;
public Vehicle get() {
if ("car".equals(type)) {
return new Car(seats);
} else if ("truck".equals(type)) {
return new Trunk(axles);
}
throw new AssertionError();
}
public void setType(String type) {
this.type = type;
}
public void setSeats(int seats) {
this.seats = seats;
}
public void setAxles(int axles) {
this.axles = axles;
}
}
I have an interface and a class in the tyle ibrary that is produced the interface appears and so does the class but the class has no methods exposed on it. so I cannot create an Application object in say VBA in Microsoft Word and call the methods on it, does anyone know what is wrong?
[ComVisible(true), Guid("261D62BE-34A4-4E49-803E-CC3294613505")]
public interface IApplication
{
[DispId(207)]
[ComVisible(true)]
IExporter Exporter { get; }
[DispId(202)]
[ComVisible(true)]
object CreateEntity([In] kEntityType EntityType, [In] object aParent);
[DispId(208)]
[ComVisible(true)]
string GenerateSpoolFileSpec();
}
[ComVisible(true), Guid("BA7F4588-0B51-476B-A885-8E1436EA0768")]
public class Application : IApplication
{
protected Exporter FExporter;
public Application()
{
FExporter = new Exporter();
}
[DispId(207)]
[ComVisible(true)]
public IExporter Exporter
{
get {return FExporter;}
}
[DispId(202)]
[ComVisible(true)]
public object CreateEntity([In] kEntityType EntityType, [In] object aParent)
{
switch (EntityType)
{
case TypeJob:
return new Job(this, aParent);
case kappEntityType.kappEntityTypePage:
return new Page(this, aParent);
}
return null;
}
[DispId(208)]
[ComVisible(true)]
public string GenerateSpoolFileSpec()
{
string path = string.Format(JOB_PARAMS_PATH_SKELETON, SpoolFolder, DateTime.Now.ToString("yyyy.MM.dd.hh.mm.ss.fff"));
return path;
}
}
Got it, don’t let dotnet handle it for you on the interface put an interfacetype e.g.
[ComVisible(true), Guid("261D62BE-34A4-4E49-803E-CC3294613505"), InterfaceType(ComInterfaceType.InterfaceIsDual)]
On the class use a classinterface e.g
[ComVisible(true), Guid("BA7F4588-0B51-476B-A885-8E1436EA0768"), ClassInterface(ClassInterfaceType.None)]
I am re engineering an MVC3 app to take all linq out of controllers and in to proper layers.
I have got this as my structure SQL --> EF --> Repository --> Service --> Controller. I am using interfaces.
When compiling I am getting this error:
gpc.data.service.roleService does not implement interface member gpc.data.interfaces.iroleservice.HolderNamesbyRoleID(int).
I am totally new to proper architecture so apologies if this is blindingly obvious lol. Here is some code:
Repository:
namespace gpc.Data.Repositories
{
public class roleRepository :gpc.Data.Interfaces.IRoleRepository
{
private gpc.Models.gpcEntities _entities = new Models.gpcEntities();
public HolderNames HolderNamesbyRoleID(int roleid)
{
return (from i in _entities.HolderNames
where i.roleid == roleid select i).FirstOrDefault();
}
}
}
I then have an interface:
namespace gpc.Data.Interfaces
{
public interface IRoleRepository
{
HolderNames HolderNamesbyRoleID(int roleid);
}
}
Then I have the service:
namespace gpc.Data.Service
{
public class roleService : gpc.Data.Interfaces.IRoleService
{
private ModelStateDictionary _modelState;
private gpc.Data.Interfaces.IRoleRepository _repository;
public roleService(ModelStateDictionary modelState)
{
_modelState = modelState;
_repository = new gpc.Data.Repositories.roleRepository();
}
public roleService(ModelStateDictionary modelState,
gpc.Data.Repositories.roleRepository repository)
{
_modelState = modelState;
_repository = repository;
}
public HolderNames HolderNames(int roleid)
{
return _repository.HolderNamesbyRoleID(roleid);
}
}
}
I then have another interface:
namespace gpc.Data.Interfaces
{
public interface IRoleService
{
HolderNames HolderNamesbyRoleID(int roleid);
}
}
I created a very simple ienumerable in this structure and I was able to get data on to the view through the controller as i would expect. I guess that as this one is a bit more complicated that a select everything and throw it at a view I must have missed something. I don't know if it makes a difference, but "holdernames" is a SQL view as opposed to a table.
Any help greatly appreciated
It's basically just what your compiler error shows. Your IRoleService interface defines a method named HolderNamesbyRoleID, but in your implementation you only have a method named HolderNames.
I assume this is just a mistype on your part.
Interface only contains the signature. You have to write actual implementation in class where you have implemented your interface. In your case you have define method HolderNamesbyRoleID in IRoleRepository but you have not implemented this method in roleService class. You must have to implement HolderNamesbyRoleID in roleService class.
Your roleService class code becomes like below.
namespace gpc.Data.Service
{
public class roleService : gpc.Data.Interfaces.IRoleService
{
private ModelStateDictionary _modelState;
private gpc.Data.Interfaces.IRoleRepository _repository;
public roleService(ModelStateDictionary modelState)
{
_modelState = modelState;
_repository = new gpc.Data.Repositories.roleRepository();
}
public roleService(ModelStateDictionary modelState,
gpc.Data.Repositories.roleRepository repository)
{
_modelState = modelState;
_repository = repository;
}
public HolderNames HolderNamesbyRoleID(int roleid)
{
return _repository.HolderNamesbyRoleID(roleid);
}
}
}
Refer interface for more info.
My enums are stored as int in mongodb (from C# app). Now in Java, when I try to retrieve them, it throws an exception (it seems enum can be converted from string value only). Is there any way I can do it?
Also when I save some collections into mongodb (from Java), it converts enum values to string (not their value/cardinal). Is there any override available?
This can be achieved by writing mongodb-converter on class level but I don't want to write mondodb-converter for each class as these enums are in many different classes.
So do we have something on the field level?
After a long digging in the spring-mongodb converter code,
Ok i finished and now it's working :) here it is (if there is simpler solution i will be happy see as well, this is what i've done ) :
first define :
public interface IntEnumConvertable {
public int getValue();
}
and a simple enum that implements it :
public enum tester implements IntEnumConvertable{
vali(0),secondvali(1),thirdvali(5);
private final int val;
private tester(int num)
{
val = num;
}
public int getValue(){
return val;
}
}
Ok, now you will now need 2 converters , one is simple ,
the other is more complex. the simple one (this simple baby is also handling the simple convert and returns a string when cast is not possible, that is great if you want to have enum stored as strings and for enum that are numbers to be stored as integers) :
public class IntegerEnumConverters {
#WritingConverter
public static class EnumToIntegerConverter implements Converter<Enum<?>, Object> {
#Override
public Object convert(Enum<?> source) {
if(source instanceof IntEnumConvertable)
{
return ((IntEnumConvertable)(source)).getValue();
}
else
{
return source.name();
}
}
}
}
the more complex one , is actually a converter factory :
public class IntegerToEnumConverterFactory implements ConverterFactory<Integer, Enum> {
#Override
public <T extends Enum> Converter<Integer, T> getConverter(Class<T> targetType) {
Class<?> enumType = targetType;
while (enumType != null && !enumType.isEnum()) {
enumType = enumType.getSuperclass();
}
if (enumType == null) {
throw new IllegalArgumentException(
"The target type " + targetType.getName() + " does not refer to an enum");
}
return new IntegerToEnum(enumType);
}
#ReadingConverter
public static class IntegerToEnum<T extends Enum> implements Converter<Integer, Enum> {
private final Class<T> enumType;
public IntegerToEnum(Class<T> enumType) {
this.enumType = enumType;
}
#Override
public Enum convert(Integer source) {
for(T t : enumType.getEnumConstants()) {
if(t instanceof IntEnumConvertable)
{
if(((IntEnumConvertable)t).getValue() == source.intValue()) {
return t;
}
}
}
return null;
}
}
}
and now for the hack part , i personnaly didnt find any "programmitacly" way to register a converter factory within a mongoConverter , so i digged in the code and with a little casting , here it is (put this 2 babies functions in your #Configuration class)
#Bean
public CustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<Converter<?, ?>>();
converters.add(new IntegerEnumConverters.EnumToIntegerConverter());
// this is a dummy registration , actually it's a work-around because
// spring-mongodb doesnt has the option to reg converter factory.
// so we reg the converter that our factory uses.
converters.add(new IntegerToEnumConverterFactory.IntegerToEnum(null));
return new CustomConversions(converters);
}
#Bean
public MappingMongoConverter mappingMongoConverter() throws Exception {
MongoMappingContext mappingContext = new MongoMappingContext();
mappingContext.setApplicationContext(appContext);
DbRefResolver dbRefResolver = new DefaultDbRefResolver(mongoDbFactory());
MappingMongoConverter mongoConverter = new MappingMongoConverter(dbRefResolver, mappingContext);
mongoConverter.setCustomConversions(customConversions());
ConversionService convService = mongoConverter.getConversionService();
((GenericConversionService)convService).addConverterFactory(new IntegerToEnumConverterFactory());
mongoConverter.afterPropertiesSet();
return mongoConverter;
}
You will need to implement your custom converters and register it with spring.
http://static.springsource.org/spring-data/data-mongo/docs/current/reference/html/#mongo.custom-converters
Isn't it easier to use plain constants rather than an enum...
int SOMETHING = 33;
int OTHER_THING = 55;
or
public class Role {
public static final Stirng ROLE_USER = "ROLE_USER",
ROLE_LOOSER = "ROLE_LOOSER";
}
String yourRole = Role.ROLE_LOOSER
I have a Singleton class that uses the thread-safe Singleton pattern from Jon Skeet as seen in the TekPub video. The class represents a cached list of reference data for dropdowns in an MVC 3 UI.
To get the list data the class calls a static method on a static class in my DAL.
Now I'm moving into testing an I want to implement an interface on my DAL class but obviously cannot because it is static and has only one static method so there's no interface to create. So I want to remove the static implementation so I can do the interface.
By doing so I can't call the method statically from the reference class and because the reference class is a singleton with a private ctor I can't inject the interface. How do I get around this? How do I get my interface into the reference class so that I can have DI and I can successfully test it with a mock?
Here is my DAL class in current form
public static class ListItemRepository {
public static List<ReferenceDTO> All() {
List<ReferenceDTO> fullList;
... /// populate list
return fullList;
}
}
This is what I want it to look like
public interface IListItemRepository {
List<ReferenceDTO> All();
}
public class ListItemRepository : IListItemRepository {
public List<ReferenceDTO> All() {
List<ReferenceDTO> fullList;
... /// populate list
return fullList;
}
}
And here is my singleton reference class, the call to the static method is in the CheckRefresh call
public sealed class ListItemReference {
private static readonly Lazy<ListItemReference> instance =
new Lazy<ListItemReference>(() => new ListItemReference(), true);
private const int RefreshInterval = 60;
private List<ReferenceDTO> cache;
private DateTime nextRefreshDate = DateTime.MinValue;
public static ListItemReference Instance {
get { return instance.Value; }
}
public List<SelectListDTO> SelectList {
get {
var lst = GetSelectList();
lst = ReferenceHelper.AddDefaultItemToList(lst);
return lst;
}
}
private ListItemReference() { }
public ReferenceDTO GetByID(int id) {
CheckRefresh();
return cache.Find(item => item.ID == id);
}
public void InvalidateCache() {
nextRefreshDate = DateTime.MinValue;
}
private List<SelectListDTO> GetSelectList() {
CheckRefresh();
var lst = new List<SelectListDTO>(cache.Count + 1);
cache.ForEach(item => lst.Add(new SelectListDTO { ID = item.ID, Name = item.Name }));
return lst;
}
private void CheckRefresh() {
if (DateTime.Now <= nextRefreshDate) return;
cache = ListItemRepository.All(); // Here is the call to the static class method
nextRefreshDate = DateTime.Now.AddSeconds(RefreshInterval);
}
}
}
You can use the singleton based on instance(not based on static), for which you can declare interface like this.
public interface IListItemRepository
{
List<ReferenceDTO> All();
}
public class ListItemRepository : IListItemRepository
{
static IListItemRepository _current = new ListItemRepository();
public static IListItemRepository Current
{
get { return _current; }
}
public static void SetCurrent(IListItemRepository listItemRepository)
{
_current = listItemRepository;
}
public List<ReferenceDTO> All()
{
.....
}
}
Now, you can mock IListItemRepository to test.
public void Test()
{
//arrange
//If Moq framework is used,
var expected = new List<ReferneceDTO>{new ReferneceDTO()};
var mock = new Mock<IListItemRepository>();
mock.Setup(x=>x.All()).Returns(expected);
ListItemRepository.SetCurrent(mock.Object);
//act
var result = ListItemRepository.Current.All();
//Assert
Assert.IsSame(expected, result);
}
Which DI framework are you using? Depending on your answer, IOC container should be able to handle single-instancing so that you don't have to implement your own singleton pattern in the caching class. In your code you would treat everything as instanced classes, but in your DI framework mappings you would be able to specify that only one instance of the cache class should ever be created.
One way to test it would be if you refactor your ListItemReference by adding extra property:
public sealed class ListItemReference {
...
public Func<List<ReferenceDTO>> References = () => ListItemRepository.All();
...
private void CheckRefresh() {
if (DateTime.Now <= nextRefreshDate) return;
cache = References();
nextRefreshDate = DateTime.Now.AddSeconds(RefreshInterval);
}
}
And then in your test you could do:
ListItemReference listReferences = new ListItemReference();
listReferences.References = () => new List<ReferenceDTO>(); //here you can return any mock data
Of course it's just temporary solution and I would recommend getting rid of statics by using IoC/DI.