Swift:Class cannot be declared public because its Super class is internal - ios

I am trying to declare the class as public as shown below
class RewardsAndRedemptionModel:BaseObject {
var rewardHistory :[RewardHistoryModel]!
}
This is where i am trying to make the class public but i could not.
public class RewardHistoryModel :BaseObject {
var rewardValue : String!
var recordedByName : String!
var rewardFor : String!
}
Even i read the documentations available on Internet i couldn't get it please help me out.

The compiler tells you that you can't make it public because the super class is internal. The compiler isn't lying, you know.
No subclass can be more accessible than its super class. Why? Think about it this way, a subclass has all the properties and members that its super class has. If this restriction didn't exist, then access modifiers will not be as useful anymore. You have an internal class. Someone else subclasses your internal class and declare it as public. Now encapsulation is broken. Things that you don't want to be accessed can now be accessed through the subclass.
In other words, if a subclass is more accessible than its super class, then the access modifier of the super class loses effect. That's why the compiler has this restriction: to remind you that what you're writing can make the super class' access modifier lose effect. You're probably doing the wrong thing.
To fix the problem, declare BaseClass and its super classes as public.

Swift 3
You need to declare the access level of the RewardHistoryModel & BaseObject class & their internal members like functions or variables as public or open (open is available in swift 3).
public class BaseObject {
// set member of this class as public that you want to access outside (Project/Framework Level)
}
public class RewardHistoryModel :BaseObject {
// set members as public or open - // open is available in swift 3.
public (or open) var rewardValue : String!
public (or open) var recordedByName : String!
public (or open) var rewardFor : String!
}
As stated in the documentation (The Swift Programming Language - Access Control) :
A public variable cannot be defined as having an internal or private
type, because the type might not be available everywhere that the
public variable is used.
Classes are declared as internal by default, so you have to add the public keyword to make them public.
A similar rule exists for functions as well.
A function cannot have a higher access level than its parameter types and return type, because the function could be used in situations where its constituent types are not available to the surrounding code.

You have to declare BaseObject class as public as well.

Related

Dart implements/extends for abstract class

For abstract classes is there difference between implements and extends? Which one should I use? In Java for interfaces you would use implements, but I see dart doesn't have interfaces and both implements/extends work. If I want to declare abstract class for my api methods, should I use implements or extends?
void main() {
User user = new User();
user.printName();
}
abstract class Profile {
String printName();
}
class User extends Profile {
#override
String printName() {
print("I work!!");
return "Test";
}
}
All classes in Dart can be used as interfaces. A class being abstract means you cannot make an instance of the class since some of its members might not be implemented.
extends means you take whatever a class already have of code and you are then building a class on top of this. So if you don't override a method, you get the method from the class you extends from. You can only extend from one class.
implements means you want to just take the interface of class but come with your own implementation of all members. So your class ends up being compatible with another class but does not come with any of the other class's implementation. You can implement multiple classes.
A third options, which you did not mention, is mixin which allow us to take the implementation of multiple mixin defined classes and put them into our own class. You can read more about them here: https://dart.dev/guides/language/language-tour#adding-features-to-a-class-mixins

Ninject is reusing instances which are explicitly defined InTransientScope()

I am experiencing an issue, and I have come to a dead end on how to debug and resolve this.
I have an MVC application which is using Ninject for IoC and DI.
One of my dependencies is IApplicationLogger which I am currently implementing using Log4Net.
In my NinjectWebCommon I am binding my IApplicationLogger as follows:
kernel.Bind<IApplicationLogger>()
.ToMethod(ctx =>
{
string configFile = System.Configuration.ConfigurationManager.AppSettings["log4netconfigfilelocation"];
log4net.Config.XmlConfigurator.Configure(new System.IO.FileInfo(HttpContext.Current.Server.MapPath(configFile)));
var name = ctx.Request.Target.Member.DeclaringType.FullName;
var log4Netlogger = log4net.LogManager.GetLogger(name);
return new Log4NetApplicationLogger(log4Netlogger);
}).InTransientScope();
All fairly straight forward stuff.
However, I am finding that the first instance of IApplicationLogger which is activated is then passed to all constructors which require an IApplicationLogger instance.
for example I have the following
public class A : IA
{
public A(IB bclass, IC cclass, IApplicationLogger logger){}
}
public class B : IB
{
public B(IApplicationLogger logger){}
}
public class C : IC
{
public C(IApplicationLogger logger){}
}
I have set breakpoints on each constructor and also the line in my NinjectWebCommon kernel.Bind().ToMethod(ctx =>
What I see is this:
Break point in NinjectWebCommon is hit, and I can see
ctx.Request.Target.Member.DeclaringType.FullName is Class B.
Break point in Constructor Class B is hit and logger
instance is correct
Break point in Constructor Class C is hit, and
logger instance has a logger name of Type Class B
Break point in Constructor Class A is hit, and logger instance has a logger
name of Class B
I would expect the breakpoint within NinjectWebCommon to be hit for each new instance of IApplicationLogger that is required, but it is only hit once for the first activation for the instance of Class B.
I have tried my Binding without the InTransientScope() option.
My IA, IB and IC bindings are defined InSingletonScope(). This shouldn't cause an issue as I am expecting Ninject to activate an instance of each, each with it's own instance of IApplicationLogger.
The result of the binding I am seeing currently is that logging statements I output in say Class A are being recorded in the Log as being from a logger name for class of type B.
Can anyone suggest how I can diagnose why Ninject is reusing the TransientScoped() IApplicationLogger, or how I can peek under the hood of what Ninject is doing so that I can analyse this in greater detail?
For anyone interested I didn't discover the underlying issue here, but I have opted to inject an ILoggerFactory with a single method .GetLogger(string typename), allowing my classes to request their own Logger and passing their own Type name.
This way I can ensure that each Class has it's own logger, with the LoggerName matching the Class TypeName.

How do I clean up my Delegate class to be cleaner?

I am writing an SDK and wanted to know how to write things more cleanly.
For example, I have a GodManager delegate class (which will be the central class that a user can interact with) (this is pseudocode-ish):
public class GodManager {
private CloudApi cloudApi;
private SensorApi sensorApi;
private CacheApi cacheApi;
.
. And about 5 more API classes of similar sorts
.
GodManager() {
cloudApi = new CloudApi();
sensorApi = new SensorApi()
cacheApi = new CacheApi();
}
public void someCloudApiMethodAccess() {
cloudApi.someCloudApiMethodAccess();
}
.
.
. And I have about 25 other methods where GodManager delegates to API classes
.
}
How do I allow access for my users via GodManager, but remove these 25 methods that are just proxy methods for each Api class?
I know that Android Wear does something with:
public class Wearable {
public static final com.google.android.gms.wearable.DataApi DataApi;
public static final com.google.android.gms.wearable.MessageApi MessageApi;
public static final com.google.android.gms.wearable.NodeApi NodeApi;
}
Where you can access these APIs in your code:
Wearable.DataApi.getFdForAsset(...)
So I'm guessing that I can mimic this and do something like:
class GodManager {
public static CloudApi CloudApi;
GodManager {
CloudApi = new CloudApi();
}
}
Then in my implementation classes, I can:
class ImplClass {
public void method() {
GodManager.CloudApi.someCloudApiMethodAccess()
}
}
Am I missing anything? Will there be some awkward side-effects that I haven't considered? Any advice would be greatly appreciated in an effort to clean up my GodManager.
Or maybe someone has some other examples that I can look at and learn from?
Creating public fields is usually an antipattern, although there are some legid uses. The danger lies in the fact that if a user has access to your field, it can do ANYTHING with it.
If CloudApi contains public methods or public fields of it's own, that the user should NOT mess with, then te ONLY solution is to make a huge delegate class. If you have full control over CloudApi, and/or you can ensure that it's only public members are those that may be safely, and unconditionally, accessed by others, then you can make the instance public. (which is the legid use)
(Note that making a member private and making a public getter for that method that returns the instance, is exactly the same!)
Even then, you're limiting yourself because you're defining your API (of GodManager) and you're preventing yourself from EVER extending functionality of the referenced instances. For example, you might want to make calls to CloudApi synchronized, or check parameter validity, but don't want (or can) change CloudApi. If you have delegate methods, you can extend the functionality without changing your GodManager API, and existing users don't break.

Using Log4Net inside an interface

I have an interface
public interface ILoggerService
{
void Info(string message);
void Warn(string message);
}
Then, i have a class which implements this interface and logs using Log4Net
public class Log4NetLoggerService : ILoggerService
{
private readonly ILog _logger;
public Log4NetLoggerService()
{
// this always returns Log4NetLoggerService class type
_logger = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
}
public void Info(string message)
{
_logger.Info(message);
}
}
This works fine, but the problem is that if i want to log the current class and method name, (using %class - %M), this always returns Log4NetLoggerService as the class, and as the method it returns Info as the method.
I need to get the "parent" class type, which called the logging method.
Can i inject somehow the type of the class which calls the log methods when i create the ILoggerService instance?
Have a look at the log4net source code; specifically how they implemented the ILog interface. You basically cannot use the ILog interface in your wrapper, instead you use the internal logger which accepts a parameter that instructs log4net where to look for the correct class / method in the call stack. See also this answer.
In my experience, if you need the name of the class you're logging in, you're probably logging too much and from too many places in your application. This can lead to maintenance problems. Take a look at this Stackoverflow answer to verify if you're not logging too much and if you're not violating the SOLID principles.

Avoiding Duplication of RiakKey in BaseEntity and derived classes

I have a base class which is a Riak entity, and some derived classes that extends BaseEntity.
BaseEntity has a field named Identifier which is annotated as #RiakKey.
but apparently this is not enought. It seems that I must have the Identifier field, with the #RuiakKey anotation in each derived class, otherwise I get this exception:
com.basho.riak.client.convert.NoKeySpecifedException
at com.basho.riak.client.bucket.DefaultBucket.fetch(DefaultBucket.java:535)
at com.att.cso.omss.datastore.riak.controllers.RiakBaseController.isEntityExist(RiakBaseController.java:130)
at com.att.cso.omss.datastore.riak.controllers.RiakBaseController.createEntity(RiakBaseController.java:94)
at com.att.cso.omss.datastore.riak.controllers.RiakBaseController.createServiceProvider(RiakBaseController.java:234)
at com.att.cso.omss.datastore.riak.App.serviceProviderTests(App.java:62)
at com.att.cso.omss.datastore.riak.App.main(App.java:38)
So, my current implementation looks like this (duplication of the identifier field):
public class BaseEntity{
#RiakKey
#JsonProperty("Id")
protected String identifier;
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
.
.
.
public class Service extends BaseEntity{
#RiakKey
#JsonProperty("Id")
protected String identifier;
public String getIdentifier() {
return identifier;
}
public void setIdentifier(String identifier) {
this.identifier = identifier;
}
is there a way to avoid this duplication?
UPDATED: Thanks to a contribution by someone who saw this question, this is will now be supported as of the 1.0.7 client release. See: https://github.com/basho/riak-java-client/pull/180
Original Answer:
Short answer: No, there's not a way around it currently.
The reason is the com.basho.riak.client.convert.reflect.AnnotationScanner class, how it looks for these annotations, and what we allow the scoping of the fields to be.
It uses Class.getDeclaredFields() which only gets the fields explicitly declared in the class, not inherited ones. The reason for this is that it gets private and protected members, whereas Class.getFields() would get inherited ones but only if they were declared public in a parent class.
One simple way around this would be to recursively scan each parent class up the inheritance tree. Because of how we cache the annotated fields for domain objects this would only be a one time hit and probably wouldn't be too terrible of a thing to do.
If this is something you'd be interested in having added to the client, please feel free to open an issue on github (or code & submit it yourself, of course - we're always thankful for community submissions!).

Resources