I'm trying to create an abstract class Firestorable which will ensure that subclasses override a named constructor fromMap(Map<String, dynamic> map)
The code looks like this ...
abstract class Firestorable {
/// Concrete implementations will convert their state into a
/// Firestore safe [Map<String, dynamic>] representation.
Map<String, dynamic> toMap();
/// Concrete implementations will initialize its state
/// from a [Map] provided by Firestore.
Firestorable.fromMap(Map<String, dynamic> map);
}
class WeaponRange implements Firestorable {
int effectiveRange;
int maximumRange;
WeaponRange({this.effectiveRange, this.maximumRange});
#override
WeaponRange.fromMap(Map<String, dynamic> map) {
effectiveRange = map['effectiveRange'] ?? 5;
maximumRange = map['maximumRange'] ?? effectiveRange;
}
#override
Map<String, int> toMap() {
return {
'effectiveRange': effectiveRange,
'maximumRange': maximumRange ?? effectiveRange,
};
}
}
I don't get any errors when I do this, however I also don't get a compile error when I leave out the concrete implementation of the fromMap(..) constructor.
For example the following code will compile without any errors:
abstract class Firestorable {
/// Concrete implementations will conver thier state into a
/// Firestore safe [Map<String, dynamic>] representation.
Map<String, dynamic> convertToMap();
/// Concrete implementations will initialize its state
/// from a [Map] provided by Firestore.
Firestorable.fromMap(Map<String, dynamic> map);
}
class WeaponRange implements Firestorable {
int effectiveRange;
int maximumRange;
WeaponRange({this.effectiveRange, this.maximumRange});
// #override
// WeaponRange.fromMap(Map<String, dynamic> map) {
// effectiveRange = map['effectiveRange'] ?? 5;
// maximumRange = map['maximumRange'] ?? effectiveRange;
// }
#override
Map<String, int> convertToMap() {
return {
'effectiveRange': effectiveRange,
'maximumRange': maximumRange ?? effectiveRange,
};
}
}
Am I not able to define an abstract named constructor and have it be a require implementation in a concrete class? If not, what would be the correct way to do this?
As stated in the official guide for the Dart Language constructors aren’t inherited so you can't enforce a factory constructor to subclasses. To ensure an implementation it should be part of the class' interface which constructors are not. You can check these related stackoverflow questions for more information:
How to declare factory constructor in abstract classes
How do i guarentee a certain named constructor in dart
Related
My meta listener code
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
#KafkaListener(containerFactory = "myListenerContainerFactory", autoStartup = "false")
public #interface mylistener1 {
#AliasFor(annotation = KafkaListener.class, attribute = "topics")
String[] topics();
String myattr() default "";
}
Consume method:
#Service
Class ConsumerService(){
#mylistener1(topics = "new.topic",myattr="new.myatr.topic")
public void consume(String message) {
LOG.info("consumer-> " + message);
}
}
I tried to get value from ApplicationContext, but it was not getting the listener.
#Autowired
ApplicationContext ctx;
Map<String, Object> allBeansWithNames = ctx.getBeansWithAnnotation(mylistener1.class);
allBeansWithNames - 0, and I am not getting class list which is having #mylistener1 annotation`your text`
I want to implement beanpostprocessor to check myattr at runtime and use it to send message`
getBeansWithAnnotation() will only find beans with classes that are so annotated (or #Bean factory methods). It doesn't look at the class methods.
Take a look at KafkaListenerAnnotationBeanPostProcessor for an example of a BPP that examines annotations and their attributes.
after using massTransit (8.0.8) I got following error :
'RoutingSlipCompleted' does not contain a definition for 'GetVariable'
and the best extension method overload
'RoutingSlipEventExtensions.GetVariable(ConsumeContext,
string, Guid)' requires a receiver of type
'ConsumeContext'
here is my code:
using MassTransit;
using MassTransit.Courier.Contracts;
using MassTransit.Courier;
public class CheckInventoriesConsumer: IConsumer<ICheckInventoryRequest>
, IConsumer<RoutingSlipCompleted>
, IConsumer<RoutingSlipFaulted>
{
private readonly IEndpointNameFormatter _formatter;
public CheckInventoriesConsumer(IEndpointNameFormatter formatter)
{
_formatter = formatter;
}
public async Task Consume(ConsumeContext<ICheckInventoryRequest> context)
{
var routingSlip = CreateRoutingSlip(context);
await context.Execute(routingSlip);
}
private RoutingSlip CreateRoutingSlip(ConsumeContext<ICheckInventoryRequest> context)
{ // lot of code here
}
public async Task Consume(ConsumeContext<RoutingSlipCompleted> context)
{
// error is here
context.Message.GetVariable<Guid>(nameof(ConsumeContext.RequestId));
throw new NotImplementedException();
}
}
It is not going to find GetVariable method from MassTransit.Courier and I encounter with this error.
As you've already found based upon your comments:
context.GetVariable<Guid>(nameof(ConsumeContext.RequestId));
Is the right solution.
MassTransit Version 8 has more extensive serialization support, and the SerializationContext (from ConsumeContext) is needed to properly deserialize the variable from the routing slip event.
I'm currently working on a simple project crypto_wallet. State management (BLoC) and Value Equality (freezed) creating CRUD operation of DB (Firebase) and in the watch method, I use StreamSubcription code is :
#injectable
class CoinWatcherBloc extends Bloc<CoinWatcherEvent, CoinWatcherState> {
final ICoinRepository _repository;
CoinWatcherBloc(this._repository, this._coinStreamSubscription) :
super(CoinWatcherState.initial());
StreamSubscription<Either<CoinFailure, KtList<CoinEntity>>>? _coinStreamSubscription;
#override
Stream<CoinWatcherState> mapEventToState(CoinWatcherEvent event) async* {
yield* event.map(
watchCoin: (e) async* {
yield CoinWatcherState.loadInProgress();
await _coinStreamSubscription?.cancel();
_coinStreamSubscription = _repository.watchCoin().listen(
(failureOrSuccess) => add(
CoinWatcherEvent.coinsReceived(failureOrSuccess),
),
);
},
coinsReceived: (e) async* {
yield e.failureOrCoin.fold(
(f) => CoinWatcherState.loadFailure(f),
(coin) => CoinWatcherState.loadSuccess(coin),
);
},
);
}
#override
Future<void> close() async {
await _coinStreamSubscription?.cancel();
return super.close();
}
}
And at last I closed the stream. I inject all third party modules on #lazySingleton :
#module
abstract class FirebaseInjectableModule {
#lazySingleton
FirebaseAuth get firebaseAuth => FirebaseAuth.instance;
#lazySingleton
FirebaseFirestore get firebaseFirestore => FirebaseFirestore.instance;
#lazySingleton
GoogleSignIn get googleSignIn => GoogleSignIn();
}
Then It says :
Object/factory with type StreamSubscription<Either<CoinFailure, KtList<CoinEntity>>> is not
registered inside GetIt.
(Did you accidentally do GetIt sl=GetIt.instance(); instead of GetIt sl=GetIt.instance;
Did you forget to register it?)
If I also register this class like this.
#lazySingleton
StreamSubcription get streamSubcription => StreamSubcription();
Then it throws compile time error that abstract classes can't be instantiated like the all Third Party Classes I've registered. How to inject abstract classes? Is there any other way to do this? or I shouldn't use StreamSubcription something else? I'd be thankful <3 :)
You should not add this._coinStreamSubscription to your bloc's constructor. Remove it from the constructor, and declare it as a late final instance.
class CoinWatcherBloc extends Bloc<CoinWatcherEvent, CoinWatcherState> {
final ICoinRepository _repository;
CoinWatcherBloc(this._repository) :
super(CoinWatcherState.initial());
late final StreamSubscription<Either<CoinFailure, KtList<CoinEntity>>>? _coinStreamSubscription;
get_it was trying to inject the abstract streamSubscription since it is in your constructor. And you do not need this. Also, if you look at it from a testing perspective, there is no need to mock the streamSubscription, you can instead mock the class that supplies data to it - which is the repository in this case
I generally just inject the implementation of the abstract class like
#LazySingleton(as:AbstractClass).
I am writing a Firestore Model abstract class that handles common operations. Each model matches a collection in Firestore... I want to refer to that both from a create instance and before the instance exists. But I can't make collectionPath static because I can't override static methods, variables, getters, etc... I get that.
Could create an instance as needed maybe Model().collectionPath but I couldn't get that to work.
Is there a way to do this? How are others making these types of Models?
This is what I'm trying to do:
abstract class Model {
String get collectionPath => "";
void create() async {
CollectionReference collection = FirebaseFirestore.instance.collection(this.collectionPath);
this.reference = await collection.add(this.toMap());
}
static Stream<QuerySnapshot> snapshots() {
return FirebaseFirestore.instance.collection(this.collectionPath).snapshots();
}
//...
class User extends Model {
String get collectionPath => "users";
//...
I want to be able add an existing instance to the firestore:
User user = User("Values");
user.create();
And I'd also like to load all the users before I've created any particular one:
Widget _buildBody(BuildContext context) {
return StreamBuilder<QuerySnapshot>(
stream: User.snapshots(),
I've RESTful service Spring MVC based.
The service has a RESTful resource method that returns the following response:
public class OperationalDataResponse<T> {
private String status;
private String statusMessage;
private T result;
//getters and setters
}
This response object encapsulates the result object of type T.
On the client side I use RestTemplate with GsonHttpMessageConverter added.
I get the response from service as a ResponseEntity
I handle the generic response with runtime Type as below:
public class OperationalDataRestClient<REQ,RESULT_TYPE> {
public OperationalDataResponse<RESULT_TYPE> getOperationalData(String resourcePath, Map<String, Object> urlVariables, Class<RESULT_TYPE> resultType) {
//code to invoke service and get data goes here
String responseString = responseEntity.getBody();
response = GsonHelper.getInstance().fromJson(responseString, getType(OperationalDataResponse.class, resultType));
}
Type getType(final Class<?> rawClass, final Class<?> parameter) {
return new ParameterizedType() {
#Override
public Type[] getActualTypeArguments() {
return new Type[] { parameter };
}
#Override
public Type getRawType() {
return rawClass;
}
#Override
public Type getOwnerType() {
return null;
}
};
}
}
This works like a charm as long as my resultType is a non-collection class.
So, this works great from caller code:
getOperationalData(someResourcePath, someUrlVariables, MyNonGenericClass.class)
However if my resultType is a collection (say, List<String> or List<MyNonGenericClass>)
then I don't know how to pass the resultType Class from the caller code.
For example, from caller code,
getOperationalData(someResourcePath, someUrlVariables, List.class)
or
getOperationalData(someResourcePath, someUrlVariables, List<MyNonGenericClass>.class)
throws compilation error.
I tried passing on ArrayList.class as well but that too doesn't work.
Any suggestion how can I pass a generic collection as a resultType from caller code (in other words, as an example, how can I pass the class object of a List<String> or List<MyNonGenericClass> from caller code ?)
If you know that ResultType is coming as a List, Then it will obvious fail like you said compilation issue.Why? because you are trying to send a List when you method only accepts a single value.In order to over come that issue you will have to change the method arguments to the following
public OperationalDataResponse<RESULT_TYPE> getOperationalData(String resourcePath, Map<String, Object> urlVariables, List<Class<RESULT_TYPE>> resultType){
....
}
and you will have to make some slight modification to getType() Method,loop it and then pass each class value to getType method like so
for(MyNonGenericClass myClass:mylist){
getType(OperationalDataResponse.class, myClass.getClass());
}