Subclassing a ParseObject Subclass (Android) - java

Is it possible to subclass subclasses of ParseObjects? I am following the directions here. My class looks like this:
#ParseClassName("Stove")
public class Stove extends ParseObject{
private String URL = "url";
private String BRAND_NAME = "brand name";
public Stove() {
//Needed for Parse
}
public Stove(String url, String brandName) {
put(URL, url);
put(BRAND_NAME, brandName);
}
public String getUrl() {
return getString(URL);
}
public String getBrandName() {
return getString(BRAND_NAME);
}
...
}
and I have a subclass of this that looks like
#ParseClassName("ElectricStove")
public class ElectricStove extends Stove{
public ElectricStove() {
}
public ElectricStove(String url, String brandName) {
super(url, brandName);
}
...
}
My Application subclass is registered in AndroidManifest.xml and has this code in onCreate():
ParseObject.registerSubclass(Stove.class);
ParseObject.registerSubclass(ElectricStove.class);
...
Parse.initialize(this, "<lots of letters>", "<more letters>");
ParseInstallation.getCurrentInstallation().saveInBackground();
I'm getting this exception
Caused by: java.lang.IllegalArgumentException: You must register this ParseObject subclass before instantiating it.
at com.parse.ParseObject.<init>(ParseObject.java:363)
at com.parse.ParseObject.<init>(ParseObject.java:324)
at <package>.Stove.<init>(Stove.java:16)
at <package>.ElectricStove.<init>(ElectricStove.java:7)
which makes me wonder if I'm going about this in the wrong way or if it's perhaps simply not possible.

It's just not possible at this point, as Parse Android SDK does not support this. Rather, as a suggestion, use an identifier to specify what type of "Stove" a particular stove object is. Take this example:
#ParseClassName("Instrument")
public class Instrument extends ParseObject {
public Instrument() {
// A default constructor is required.
}
public InstrumentType getType() {
return InstrumentType.parse(getString("type"));
}
public void setType(InstrumentType type) {
put("type", type.toString());
}
then use:
final Instrument ocarina = new Instrument();
// Since our Instruments are strongly-typed, we can provide mutators that only take
// specific types, such as Strings, ParseUsers, or enum types.
ocarina.setType(InstrumentType.WOODWIND);
This would be a work-around of sorts to allow you to perform actions on an object based on it's type. It's not perfect, but it may suit your needs. The InstrumentType is just a class used for static constants in order to access id values
Example taken from here

Related

Define default value for inherited class using lombok

So I am developing a notification service which, for now, only has a Notification and an Email entity, where Email extends Notification.
The Notification entity has a column named type which stores the type of the notification (ie: EMAIL, MESSAGE, PUSH, etc) and I want to know if there is a way to define a default value for the type column for each of the childs of Notification while using lombok.
I see that a common practice is to set the type on the constructor, like this:
public Email() {
setType("EMAIL");
}
But I am using the builder from lombok to instatiate Email, like this:
public static Email fromEmailRequest(final EmailRequest emailRequest) {
if (Objects.isNull(emailRequest)) {
return Email.builder().build();
}
Set<String> set = new LinkedHashSet<>(emailRequest.getRecipients());
return Email.builder()
.content(emailRequest.getContent())
.recipients(Lists.newArrayList(set))
.sender(emailRequest.getSender())
.subject(emailRequest.getSubject())
.type(NotificationTypeEnum.EMAIL)
.build();
}
The approach I am using now sets the type in the request DTO mapper, but I think this logic should be somewhere in the entities.
Maybe there is a better way, but you can create a constructor inside your Notification class which has the type as parameter and then manually create an all args constructor for your Email class. Lombok will use this constructor for the builder instead of generating one.
public class Notification {
private final String type;
protected Notification(String type) {
this.type = type;
}
}
#Builder
public class Email extends Notification {
private String test;
private Email(String test) {
super("EMAIL");
this.test = test;
}
}
#SuperBuilder is a bit more complex to work with, but the idea is the same. You can still write parts of the code that is normally generated by lombok yourself and change its behavior with your own code.
So you implement the build method yourself and set the type to EMAIL.
#SuperBuilder(toBuilder = true)
public class Email extends Notification {
private String test;
public static class EmailBuilderImpl extends EmailBuilder<Email, EmailBuilderImpl> {
/* Make sure the value is never accidently set to something other than `EMAIL`*/
#Override
public EmailBuilderImpl type(String type) {
if (!type.equals("EMAIL")) {
throw new UnsupportedOperationException();
}
return super.type(type);
}
public Email build() {
return new Email(type("EMAIL"));
}
}
}

Can I have a single instance of Interface

In my Android application I have a class which gives me static string values; something like this:
public class VehicleInfo {
public static String getVehicleEnginePower(boolean isNew) {
return isNew ? "1800CC" : "1600CC";
}
}
Now I have another category, so I will have to pass another Boolean, and I will get the value I need. However, these categories will keep on increasing. So I looked into the Open/Closed principle which looks promising for quick enhancement. To ensure this I will make the VehicleInfo class as an Interface and then I will have other classes implement VehicleInfo.
public interface VehicleInfo {
String getVehicleEnginePower();
}
public class NewVehicle implements VehicleInfo {
#Override
public String getVehicleEnginePower() {
return "1800CC";
}
}
and the other category classes will also be something like this. In this way I will have to add another class for all the new categories.
The question I wanted to ask is: is there a way that I can have single instance of this interface? Because in the whole application flow, a user will only be able to see one category until he switches to another category.
I don't want to instantiate these classes at multiple points. To clarify my question, I want to do something like this at the start of my application:
if (isNew) {
VehicleInfo vehicleInfor = new NewVehicle();
}
And in the whole application, whenever I call VehicleInfo.getVehicleEnginePower, it should always return engine power from the NewVehicle class.
Is something like this possible? Or am I just being silly and I will have to instantiate this interface on multiple points?
Maybe you need a singleton here
public class VehicleInfoManager {
private static VehicleInfoManager INSTANCE = new VehicleInfoManager();
private VehicleInfo currentVehicleInfo;
public static VehicleInfoManager getInstance() {
return INSTANCE;
}
public void setCurrentVehicleInfo(VehicleInfo info) {
this.currentVehicleInfo = info;
}
public String getVehicleEnginePower() {
return this.currentVehicleInfo.getVehicleEnginePower();
}
private VehicleInfoManager() {
// Constructor private by default
}
}
Then you can call it from everywhere like this
VehicleInfoManager.getInstance().getVehicleEnginePower()
//Or set current info like this
VehicleInfoManager.getInstance().setCurrentVehicleInfo(new NewVehicle())
Just be careful as currentVehicleInfo is null by default so you need to handle null pointer cases.
If I understand your question correctly.
My solution to this would be Enum
public enum VehicleEnginePower {
NEW ("1800CC"),
OLD ("1600CC"),
private final String name;
private Modes(String s) {
name = s;
}
public String toString() {
return this.name;
}
}
Then you can do
if (isNew) {
String powerOfEngine = VehicleEnginePower.NEW.toString();
}

Can the compiler verify a generic type of an object through a generic method?

First of all, sorry for the bad title. I don't know how to describe the problem in a few words (maybe not even in many)...
I am refactoring some settings in our system to be more abstract. The current solution has multiple tables in the DB, one for each settings area. In order to add a new setting, you'll need to extend the schema, the hibernate class, all transfer object classes, getters/setters, etc. I felt that this is violating OCP (open-closed principle), thus the refactoring.
I've spent some time coming up with ideas on how to implement such an abstraction. My favourite idea so far is the following:
1 enum for each settings area
1 enum value for each setting
Each setting is a SettingsDefinition<T> class using a generic type
A SettingsService is using static get/set methods with generic types
So for example, a settings area could be:
public enum SettingsABC{
A(new SettingDefinition<Integer>("A", 123)),
B(new SettingDefinition<String>("B", "Hello")),
C(new SettingDefinition<Boolean>("C", false));
private SettingDefinition settingDefinition;
SettingsABC(SettingDefinition settingDefinition) {
this.settingDefinition = settingDefinition;
}
public SettingDefinition getDefinition() {
return settingDefinition;
}
}
Where the SettingDefinition is the following:
public class SettingDefinition<T> {
private String name;
private T defaultValue;
public SettingDefinition(String name, T defaultValue) {
this.name = name;
this.defaultValue = defaultValue;
}
public String getName() {
return name;
}
public T getDefaultValue() {
return defaultValue;
}
}
And the service to get/set the values would be:
public class SettingsService {
public static <T> T getSetting(SettingDefinition setting) {
// hit db to read
// return value
}
public static <T> void setSetting(SettingDefinition setting, T value) {
// hit db to write
}
}
And the consumer would look something like this:
String value = SettingsService.getSetting(SettingsABC.B.getDefinition());
SettingsService.setSetting(SettingsABC.A.getDefinition(), 123);
My problem is that I cannot enforce a compiler type check between the generic type of the SettingDefinition inside SettingsABC and the generic type of get/set methods of the service. So in essence, I can do this:
Integer value = SettingsService.getSetting(SettingsABC.B.getDefinition());
Where B's definition is of type String.
Also, I can do this:
SettingsService.setSetting(SettingsABC.A.getDefinition(), "A");
Where A's definition is an Integer.
Is there any way to use generics to force these two different generic types match?
You can convert the enum to the class:
public final class SettingsABC<T> {
public static final SettingsABC<Integer> A =
new SettingsABC<>(new SettingDefinition<>("A", 123));
public static final SettingsABC<String> B =
new SettingsABC<>(new SettingDefinition<>("B", "Hello"));
public static final SettingsABC<Boolean> C =
new SettingsABC<>(new SettingDefinition<>("C", false));
private final SettingDefinition<T> settingDefinition;
// private constructor, so nobody else would instantiate it
private SettingsABC(SettingDefinition<T> settingDefinition) {
this.settingDefinition = settingDefinition;
}
public SettingDefinition<T> getDefinition() {
return settingDefinition;
}
}
This way individual constants will be typed. Now you can use the type arguments for SettingService as well:
public static <T> T getSetting(SettingDefinition<T> setting) {
...
}
public static <T> void setSetting(SettingDefinition<T> setting, T value) {
...
}
Although it's not an enum anymore, it can be used mostly in the same way. If you need other methods which are usually available in enum, you can mimic them like this:
public String name() {
return settingDefinition.getName();
}
#Override
public String toString() {
return settingDefinition.getName();
}
// and so on

How to use C10N library to enable a class returning translated Strings

I'd like to use the C10N library to manage translations in a Java project, but I don't understand how to use it to enable classes generate translated strings.
Please consider the following single-language example.
public interface Pet {
public String getBreed();
}
public class Dog implements Pet {
private String breed;
public Dog(String breed) {
this.breed = breed;
}
public String getBreed() {
return this.breed;
}
}
Then, I'd like to change the previous implementation to support i18n.
So, I could declare some translations using C10N:
public interface DogBreeds{
#En("dalmatian")
#It("dalmata")
String dalmatian();
#En("poodle")
#It("barboncino")
String poodle();
}
Now, I'd like to use one of these methods in a class to return a translated String.
The idea is to pass somehow the method to the class and then call it from a class' method.
In other words, the class should be able to return the correct translation based on the current locale, that may change at runtime.
public class Dog implements Pet {
public Dog(??) {
// the class should receive all the translations
// related to a specific breed
}
public String getBreed() {
// here I want to return the correct breed name translation,
// based on the current locale
return ??;
}
}
The Dog class should not access the DogBreeds interface directly. For example, Dog may be part of a library, whereas DogBreeds may be declared in the main project.
The Dog class shouldn't hold just one translation based on the current locale, but all the available translations, so that it can return the correct one if the locale changes.
Is this feasible is a clean way?
If not, what are the alternatives?
If you would like to separate DogBreed(main project) and Dog(library), then considering that your main projects references the library (and not the other way round), you'll need to introduce some other shared interface in the library, let's say, BreedNameProvider.
public interface BreedNameProvider{
String dalmatian();
String poodle();
}
Then you can pass that to Dog class constructor:
public class Dog implements Pet {
private final BreedNameProvider bnp;
public Dog(BreedNameProvider bnp) {
this.bnp = bnp;
}
public String getBreed() {
return bnp.poodle();
}
}
The implementation of BreedNameProvider can be declared in the main project, so can safely access DogBreeds interface.
Edit: You can use a more gerenic BreedNameProvider, to return the translation you need, with working locale switching at runtime:
//Declared in your library
public interface BreedNameProvider{
String getBreedName();
}
public class Dog implements Pet {
private final BreedNameProvider bnp;
public Dog(BreedNameProvider bnp) {
this.bnp = bnp;
}
public String getBreed() {
return bnp.getBreedName();
}
}
In your main project, when instantiating different types of Dog you can just pass an implementation of BreedNameProvider that will return the localized string for the breed you want:
public class MainProject{
private static final DogBreeds breeds = C10N.get(DogBreeds.class);
public void createDogs(){
//Create a poodle
Dog poodle = new Dog(new BreedNameProvider(){
#Override
public String getBreedName(){
return breeds.poodle();
}
});
//Create dalmatian
Dog dalmatian = new Dog(new BreedNameProvider(){
#Override
public String getBreedName(){
return breeds.dalmatian();
}
});
}
}
In effect, this is equivalent to "passing a method" to Dog constructor, exactly what you asked for in your original post. In java this is pretty much the only way to do it without sacrificing compile-time safety.
One alternative way to implement BreedNameProvider would be like this:
public class MainProject{
private static final DogBreeds breeds = C10N.get(DogBreeds.class);
class CodeBreedNameProvider implements BreedNameProvider{
private final String breedCode;
CodeBreedNameProvider(String breedCode){
this.breedCode = breedCode;
}
#Override
public String getBreedName(){
switch(breedCode){
case "poodle": return breeds.poodle();
case "dalmatian": return breeds.dalmatian();
//... more if needed
}
return "unknown breed code " + breedCode;
}
}
public void createDogs(){
//Create a poodle
Dog poodle = new Dog(new CodeBreedNameProvider("poodle"));
//Create dalmatian
Dog dalmatian = new Dog(new CodeBreedNameProvider("dalmatian"));
}
}
I would try:
public class Dog implements Pet {
private static final DogBreeds BREEDS = C10N.get(DogBreeds.class);
public Dog() {
// no need to pass the translations to the constructor
}
public String getBreed() {
// Since you're wanting to specify a message key dynamically,
// you need to use getString instead of BREEDS.poodle().
return BREEDS.getString(myBreed);
}
}

Generic Type From Enum & The Builder Pattern

I'm trying to create a builder pattern that uses generics to provide type checking on some of the methods. Currently I have the following working:
ParameterBuilder.start(String.class).setName("foo").setDefaultValue("Hello").build();
ParameterBuilder.start(Integer.class).setName(bar).setDefaultValue(42).build();
ParameterBuilder.start(Boolean.class).setName(bar).setDefaultValue(false).build();
Using the code:
public class ParameterBuilder<T> {
private String name;
private T defaultValue;
public static <T2> ParameterBuilder<T2> start(Class<T2> type) {
return new ParameterBuilder<T2>();
}
// Other methods excluded for example
}
So the type of the input for the setDefaultValue method is defined by what's passed into the start method, just as I want.
But now I want to extend what's being passed into start() to contain a little more information. Essentially I want to pass in a "type" for the parameters I creating. Sometimes these parameters will be things like "email", "url" etc. The default value will still be of a known type (String in those cases), so I'd like to have something like:
ParameterBuilder.start(EMAIL).setName("email").setDefaultValue("foo#bar.com").build();
ParameterBuilder.start(URL).setName("website").setDefaultValue("http://www.somewhere.com").build();
Where at the moment EMAIL & URL are enums, containing amongst other things - the class of the default value. But if I go down this route, how would I instantiate the parameter builder?
public static <T2> ParameterBuilder<T2> start(ParameterType paramType) {
Class<T2> type = paramType.getTypeClass();
// How do I instantiate my ParameterBuilder with the right type?
}
If it can't be done using enums (which I can see being the case), does anyone have a suggestion for a different solution?
I think you need one enum per class type (I don't see how you could have one enum cover several types and keep the thing working). In that case, a common generic interface could do what you want. You can then create some sort of factory to provide the enum constants if that helps.
This compiles:
static interface ParameterType<T> {}
static enum ParameterTypeEnum implements ParameterType<String> { EMAIL; }
public static void main(String[] args) {
ParameterBuilder
.start(ParameterTypeEnum.EMAIL)
.setName("email")
.setDefaultValue("foo#bar.com")
.build();
}
public static class ParameterBuilder<T> {
private String name;
private T defaultValue;
public static <T2> ParameterBuilder<T2> start(ParameterType<T2> paramType) {
return new ParameterBuilder<T2>();
}
ParameterBuilder<T> setName(String name) {
this.name = name;
return this;
}
ParameterBuilder<T> setDefaultValue(T defaultValue) {
this.defaultValue = defaultValue;
return this;
}
void build() {}
}
I'm not sure the context in what you want to use this, but I think the following might be an option.
You can follow the Open/Closed principle and create an interface Parameter and have one implementation per type. The benefit of this, is that you don't need to add a new enum value for each new Parameter you want. You can later pass the class to ParameterBuilder rather than the enum and the ParameterBuilder and Parameter would work together to build what you need.
So ParameterBuilder.start() could return an instance of the specific Parameter and the parameter might have different methods depending on the type of parameter.
I don't think this answer is really good, but hopefully can give you a hint in how to build a potential solution for your context.
You could create an object hierachie for these Email and Url types
public class DefaultType {
protected String name;
protected String defaultValue;
//some constructor
}
public class EmailType extends DefaultType {
...
}
public class URLType extends DefaultType {
...
}
then the parameter builder could look something like this:
public static ParameterBuilder start(DefaultType type) {
ParameterBuilder builder = new ParameterBuilder(type);
builder.setType(type);
return builder;
}
Then you could call it like this:
ParameterBuilder.start(new EmailType("name","value");...
does this help or dont you want to go in this direction?

Categories

Resources