My application has some settings that can be configured, and some generate warnings. I need a way to preserve those warnings even if the application has been closed.
My warnings are structured as it follows :
public class CustomWarning implements Serializable {
private final WarningType warningType; // enum
private final String title, description;
private final CustomCallback resolution;
public CustomWarning(String title, String description, CustomCallback resolution, WarningType warningType) {
this.title = title;
this.description = description;
this.resolution = resolution;
this.warningType = warningType;
}
public WarningType getWarningType(){
return warningType;
}
public String getTitle(){
return title;
}
public String getDescription() {
return description;
}
public CustomCallback getResolution() {
return resolution;
}
#Override
public boolean equals(Object obj) {
if(obj instanceof CustomWarning){
return ((CustomWarning) obj).getWarningType() == warningType;
}
return false;
}
}
The context is the following : An user, for example, wants to set the logging output to HIGH. This will decrease the performance of the app, and thus a warning is generated. This warning will contain a title ("High output") and a description ("You have set HIGH as Logging") and will be displayed in a Dialog. Here is the function that shows my warning in the Dialog :
// This will show a new dialog with title, description, and resolve/close buttons
Optional<Boolean> result = DialogFactory.getInstance().createShowWarning().showAndWait();
if(result.isPresent() && result.get())
myWarning.getResolution().run(); // calls the "callback"
By pressing the "Resolve" button on the Dialog, it will get my CustomCallback and invoke the run() function, which can be, for example, show the configuration panel for the logging options.
The CustomCallback is just an interface :
public interface CustomCallback extends Runnable, Serializable {}
What would be the best way to preserve a List<CustomWarning> warnings after closing the app ? The following have been checked, but none seemed to work correctly :
Serialization of the List<CustomWarning> : Was a bit difficult, since the serialization from the Java API also serializes the parents, and I don't want to serialize every controller I have in my app.
Serialization of the class name / method name of the callback : Couldn't find a way to call the callback without the instance of the class, which I can't always recreate or provide.
Are there any other possibilities for the ways I've mentionned, or any new ideas ? Every comment is welcome.
Also : No external library would be better
Related
I have simple document class:
public class Player {
private String name;
private String age;
}
I want to extend it with field Parameters:
public class Player {
private String name;
private String age;
private Parameters parameters;
public class Parameters {
boolean leftFooted;
boolean leftHanded;
}
}
My Mongock #Execution method would be:
#Execution
public void execution(PlayerRepository playerRepository) {
playerRepository.findAll()
.stream()
.map(this::setDefaultParameters)
.forEach(playerRepository::save);
}
with method:
private Player setDefaultParameters(Player player) {
if (player.getParameters == null) {
player.setParameters(new Parameters(false, false));
}
return player;
}
My question is - how to implement #RollbackExecution method if documents created after model extension can also have Parameters field with values 'false, false' and I just can not set Parameters field to null for all documents in database?
First, am I right on the assumption that, before executing the #Execution method, there may be some documents which already have the parameters field with some value? And, after the execution, you struggle to identify those ones amended in the actual change unit versus those that already had the parameters field?
If that’s the case, you really are not breaking anything, and you would leave the #RollbackExecution empty, and the updated documents will remain with its default value in parameters field.
If you still care, you need to somehow mark those documents that you updated in the ChangeUnit (with a flag or something), so you can filter by the flag and restore your changes.
I've saw a video where is possible to set named locators for allure report
to get view $(locatorname).click - passed:
There is code:
public class Named extends NamedBy {
private final By origin;
private String name;
public Named(By origin) {
this.origin = origin;
}
public Named as(String name) {
this.name = name;
}
#Override
public String toString() {
return Objects.nonNull(name) ? name : this.origin.toString();
}
#Override
public List<WebElement> findElements(SearchContext context) {
return new Named(By.id(id));
}
}
And code for elements:
SelenideElement button = $(id("someid").**as("locatorName")**)
and then should be possible to work with this element.
But i can't.
I dont have method as when i try to create selenideElement.
Pls help. such report is mush more readble.
video URL: https://youtu.be/d5gjK6hZHE4?t=1300
Your example doesn't seem to be valid. At least, a method as must return this. Moreover, id in the overridden findElements is missing. Plus, it's not really clear why you extend NamedBy instead of By.
Anyway, that's just a wrapper around By. To see those locators' names in report you have to follow a previous example in a video first (event listener), before completing NamedBy implementation.
P.S. To make it works the same way as was introduced in the code snippet, you have to add an additional creational logic, e.g.:
public static NamedBy id(String locator) {
return new NamedBy(By.id(locator));
}
I have a very stupid and elementary questions, however I can't seem to get around it. I am trying to pass data between 3 classes, so this is the approach I took:
Class A
public class GroupChat {
public String message;
public String myId;
public String otherID;
public GroupChat() {
}
public String getOtherID() {
return otherID;
}
public void setOtherID(String otherID) {
this.otherID = otherID;
}
public String getMyId() {
return myId;
}
public void setMyId(String myId) {
this.myId = myId;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
Class B - which generates the data on button click
GroupChat chat = new GroupChat();
chat.setParticipants(participants);
chat.setMyId(userId);
chat.setOtherID(id);
chat.setMessage(message);
When I print out the log of these variables in the GroupChat class, all is perfect.
However, when I attempt to use the getters to get data to class C, which is where I need them, they are returning a null value.
Class C
GroupChat chat = new GroupChat();
chat.getMessage(),
chat.getItemView(),
chat.getMyId(),
chat.getOtherID());
I even tried to log the data in the GroupChat class. When I enter the data, using the setters, everything is fine, however when logging the data on the getters, these are returning null. There must be something in the GroupChat class which is nullifying the variables.
Can someone please point me to the right direction?
Thanks a million.
Each time you call:
GroupChat chat = new GroupChat();
you are creating new object with default values (e.g. 0, nulls).
If you want to use your object "B" you have to return it from the function where you call setters.
E.g.
public GroupChat getDataAfterButtonPress() {
GroupChat chat = new GroupChat();
chat.setParticipants(participants);
chat.setMyId(userId);
chat.setOtherID(id);
chat.setMessage(message);
return chat;
}
Then, you can use this object later in your code:
GroupChat result = getDataAfterButtonPress();
It is hard to conclude without full code. The only problem I can see is that you use different instances in both case. When in class C, you create a new GroupChat instead of passing the one you create in class B.
I use this great Java library for converting a text to speech using Google Translate Unofficial API.
Using this code it is able to "read" the text in English (see Language.ENLGISH):
Audio audio = Audio.getInstance();
InputStream sound = audio.getAudio("I am a bus", Language.ENGLISH);
audio.play(sound);
I have a list (a combobox) with all languages.
How can I convert a string that is "ENGLISH" into the field Language.ENGLISH?
I don't want to use a lot of ifs in the code (if (mySelectedLanguage.equals("ENGLISH") // ...Language.English).
I already tried with:
Language["ENGLISH"] inspired from Javascript, but it doesn't work
Language.class.getField("ENGLISH").toString() (toString because their types are String: public static final String ENGLISH)
Which is the correct way that will really work?
Edit: I already asked here how to get the languages. Maybe it helps us to find the answer.
If you want to get value of public static field
then instead of
Language.class.getField("ENGLISH").toString();
use
(String)Language.class.getField("ENGLISH").get(null);
null indicates that you don't want to get field from some object, but rather from entire class (which in case of static variable is desired behavior)
But if it is possible I would recommend rewriting your Language class to enum and using Language.valueOf("ENGLISH")
Create your own enum to store these values. This is good practice regardless of your particular difficulties - by creating a façade for this third-party class, you de-couple one part of your code.
If you implement toString() as shown below, you can store these enum values directly in your combo box.
public enum Languages {
ENGLISH(Language.ENGLISH, "English"),
// etc..
;
private final String languageName;
private final String displayName;
private Languages(String languageName, String displayName) {
this.languageName = languageName;
this.displayName = displayName;
}
public String getLanguageString() {
return languageName;
}
public String getDisplayString() {
return displayName;
}
public static Languages fromString(String languageString) {
for (Language l : values()) {
if (l.getLanguageString().equals(languageString)) {
return l;
}
}
return null;
}
// optional
#Override
public String toString() {
return displayName;
}
}
Maybe choose a better name than Languages - I'm not feeling very inspired.
Let's say I have an abstract class (BaseThing). It has one required parameter ("base required") and one optional parameter ("base optional"). I have a concrete class that extends it (Thing). It also has one required parameter ("required") and one optional parameter ("optional"). So something like:
public abstract class BaseThing {
public static final String DEFAULT_BASE_OPTIONAL = "Default Base Optional";
private final String baseRequired;
private String baseOptional = DEFAULT_BASE_OPTIONAL;
protected BaseThing(final String theBaseRequired) {
this.baseRequired = theBaseRequired;
}
final void setBaseOptional(final String newVal) {
this.baseOptional = newVal;
}
public final void selfDescribe() {
System.out.println("Base Required: " + baseRequired);
System.out.println("Base Optional: " + baseOptional);
selfDescribeHook();
}
protected abstract void selfDescribeHook();
}
and:
public final class Thing extends BaseThing {
public static final String DEFAULT_OPTIONAL = "Default Optional";
private final String required;
private String optional = DEFAULT_OPTIONAL;
Thing(final String theRequired, final String theBaseRequired) {
super(theBaseRequired);
required = theRequired;
}
#Override
protected void selfDescribeHook() {
System.out.println("Required: " + required);
System.out.println("Optional: " + optional);
}
void setOptional(final String newVal) {
optional = newVal;
}
}
I want to have a Joshua Bloch-style builder for Thing objects. More generally, though, I want to make it easy for concrete implementations of BaseThing to have builders, so what I really want (I think) is a BaseThing builder that can easily be used to make a ThingBuilder, or an OtherThingBuilder, or a SuperThingBuilder.
Is there a better way than the following that I've come up with (or are there problems with what I've come up with)?
public abstract class BaseThingBuilder<T extends BaseThing> {
private String baseOptional = BaseThing.DEFAULT_BASE_OPTIONAL;
public BaseThingBuilder<T> setBaseOptional(final String value) {
baseOptional = value;
return this;
}
public T build() {
T t = buildHook();
t.setBaseOptional(baseOptional);
return t;
}
protected abstract T buildHook();
}
and:
public final class ThingBuilder extends BaseThingBuilder<Thing> {
private final String baseRequired;
private final String required;
private String optional = Thing.DEFAULT_OPTIONAL;
public ThingBuilder(final String theRequired,
final String theBaseRequired) {
required = theRequired;
baseRequired = theBaseRequired;
}
public ThingBuilder setOptional(final String value) {
optional = value;
return this;
}
protected Thing buildHook() {
Thing thing = new Thing(required, baseRequired);
thing.setOptional(optional);
return thing;
}
}
Which can be used to build Thing objects in a manner similarly to the following:
BaseThingBuilder<Thing> builder =
new ThingBuilder("Required!", "Base Required!")
.setOptional("Optional!")
.setBaseOptional("Base Optional!");
Thing thing = builder.build();
thing.selfDescribe();
Which outputs:
Base Required: Base Required!
Base Optional: Base Optional!
Required: Required!
Optional: Optional!
One issue that I know about, but that I don't consider particularly important (though if it can be improved it would be nice to do so) is that you have to set all non-base options before you set any base option: Doing otherwise would result in a syntax error, as setBaseOptional() returns a BaseThingBuilder rather than a ThingBuilder.
Thanks in advance.
I don't think it's a good idea to think of builders that way. A hierarchy of builders usually leads to headaches and fragile code.
Cutting down the amount of code that needs to be written in the concrete builders and reusing logic from the base builder is closely tied to the domain. It's not easy to develop a general solution. But, let's try to go through an example anyway:
public interface Builder<T> {
T build();
}
public class Person {
private final String name;
//the proper way to use a builder is to pass an instance of one to
//the class that is created using it...
Person(PersonBuilder builder) {
this.name = builder.name;
}
public String getName(){ return name; }
public static class PersonBuilder implements Builder<Person> {
private String name;
public PersonBuilder name(String name){ this.name = name; return this; }
public Person build() {
if(name == null) {
throw new IllegalArgumentException("Name must be specified");
}
return new Person(this);
}
}
}
Groovy, baby! Now what? Maybe you want to add a class to represent a student. What do you do? Do you extend Person? Sure, that's valid. How about taking a more "strange" route and attempting aggregation? Yep, you can do that too... Your choice would have an affect on how you will end up implementing builders. Let's say you stick to the traditional path and extend Person (you should already starting asking yourself, does it make sense for Person to be a concrete class? If I make it abstract, do I really need a builder? If the class is abstract should the builder be abstract?):
public class Student extends Person {
private final long id;
Student(StudentBulder builder) {
super(builder);
this.id = builder.id;
}
public long getId(){ return id; }
//no need for generics, this will work:
public static class StudentBuilder extends PersonBuilder {
private long id;
public StudentBuilder id(long id){ this.id = id; return this; }
public Student build() {
if(id <= 0) {
throw new IllegalArgumentException("ID must be specified");
}
return new Student(this);
}
}
}
Ok, this looks exactly like what you wanted! So, you try it:
Person p = new PersonBuilder().name("John Doe").build();
Student s = new StudentBuilder().name("Jane Doe").id(165).build();
Looks great! Except, it doesn't compile... There's an error at line 2 and it states The method id(int) is undefined for the type Person.PersonBuilder. The problem is that PersonBuilder#name returns a builder of type PersonBuilder, which isn't what you want. In StudentBuilder you actually want the return type of name to be StudentBuilder. Now, you think ahead and realize that if anything extends StudentBuilder you'd want it to return something else entirely... Is that doable? Yes, with generics. However, it's ugly as hell and introduces quite a bit of complexity. Therefore, I refuse to post the code that illustrates it, for the fear that someone will see this thread and actually use it in their software.
You might think rearranging method calls will work (calling id before calling name): new StudentBuilder().id(165).name("Jane Doe").build(), but it won't. At least not without an explicit cast to Student: (Student)new StudentBuilder().id(165).name("Jane Doe").build() since, in this case, PersonBuilder#build is being called which has a return type of Person... This is simply unacceptable! Even if it worked without an explicit cast, it should make you wince to know that a builder's methods must be called in a certain order. Because if you don't, something won't work...
There are many more problems that would arise if you continue trying to get it to work. And even if you did get it to work, I don't think it would be easily comprehensible and certainly not elegant. Of course, feel free to prove me wrong and post your solution here.
By the way, you should also ask yourself what is an abstract builder? Because, it sounds like an oxymoron.
In the end, I believe that the scope of this question is too great. The answer is domain-specific and hard to come up with in the absence of your requirements. Just remember, the general guideline for builders is to have them be as simple as possible.
Also, take a look at a related question.
As far as I can tell if you remove the generics then
BaseThingBuilder<Thing> builder =
new ThingBuilder("Required!", "Base Required!")
changes to
BaseThingBuilder builder =
new ThingBuilder("Required!", "Base Required!")
The rest of it all remains same, including the restriction that subclass has to be initialized first. So I really don't think this warrants use of generics. Maybe I am missing something.
I seem to remember something like this from Bjarne Stroustrup, long back...