I'm trying to implement a BuilderPattern, where a subclass must extend a superclass.
Superclass:
#Getter
public abstract class CommonValidatorConfig<VC extends CommonValidatorConfig<VC>> {
private boolean canBeNull;
private boolean canBeEmpty;
public static abstract class CommonValidatorConfigBuilder<VC, VCB extends CommonValidatorConfigBuilder<VC, VCB>> {
protected boolean canBeNull;
protected boolean canBeEmpty;
#SuppressWarnings("unchecked")
public VCB canBeNull(boolean canBeNull) {
this.canBeNull = canBeNull;
return (VCB) this;
}
#SuppressWarnings("unchecked")
public VCB canBeEmpty(boolean canBeEmpty) {
this.canBeEmpty = canBeEmpty;
return (VCB) this;
}
#SuppressWarnings("unchecked")
public VCB setDefault() {
this.canBeNull = false;
this.canBeEmpty = false;
return (VCB) this;
}
public abstract VC build();
}
}
Subclass:
#Builder
#AllArgsConstructor(access = AccessLevel.PRIVATE)
public class StringValidatorConfig extends CommonValidatorConfig<StringValidatorConfig> {
public static class StringValidatorConfigBuilder extends CommonValidatorConfigBuilder<StringValidatorConfig, StringValidatorConfigBuilder> {
#Override
public StringValidatorConfig build() {
return new StringValidatorConfig(false, false); // ERROR
}
}
}
The AllArgsConstructor AccessLevel is set to PRIVATE because I want to create a new instance using only Builders.
I was expecting an AllArgsConstructor for StringValidatorConfig with two variables (canBeNull and canBeEmpty), but the AllArgsConstructor takes no arguments for the constructor.
this means that the variables of the CommonValidatorConfig are not inherited.
Any help, also tutorials/docs/references or improvements of code are welcomed.
#SuperBuilder will do all the work for you:
#Getter
#SuperBuilder
public abstract class CommonValidatorConfig {
private boolean canBeNull;
private boolean canBeEmpty;
}
#SuperBuilder
public class StringValidatorConfig extends CommonValidatorConfig {
}
That's it.
If you need to add a custom method inside your builder, you can do so by adding the class header of the (abstract) builder class and add your method. Lombok will add all the rest of its methods. I suggest you copy the class header from the delombok output (run java -jar path/to/lombok.jar delombok -p path/to/ClassWithSuperBuilder.java).
#Getter
#SuperBuilder
public abstract class CommonValidatorConfig {
private boolean canBeNull;
private boolean canBeEmpty;
public static abstract class CommonValidatorConfigBuilder<C extends CommonValidatorConfig, B extends CommonValidatorConfig.CommonValidatorConfigBuilder<C, B>> {
public B setDefault() {
this.canBeNull = false;
this.canBeEmpty = false;
return self();
}
}
}
The "experimental" status of #SuperBuilder just means it may not receive bugfixes as quickly as stable features. Furthermore, there are plans to promote #SuperBuilder to stable.
The code Lombok generates is completely type-safe, there are no unchecked type conversions. So even if you later decide that you don't want #SuperBuilder anymore, you can simply de-lombok it. The resulting code will be better than your manual solution.
I'm not sure if this is the best way, but I solved in this way:
Superclass:
I added an AllArgsConstructor with AccessLevel PROTECTED.
#Getter
#AllArgsConstructor(access = AccessLevel.PROTECTED)
public abstract class CommonValidatorConfig<VC extends CommonValidatorConfig<VC>> {
private boolean canBeNull;
private boolean canBeEmpty;
public static abstract class CommonValidatorConfigBuilder<VC, VCB extends CommonValidatorConfigBuilder<VC, VCB>> {
protected boolean canBeNull;
protected boolean canBeEmpty;
#SuppressWarnings("unchecked")
public VCB canBeNull(boolean canBeNull) {
this.canBeNull = canBeNull;
return (VCB) this;
}
#SuppressWarnings("unchecked")
public VCB canBeEmpty(boolean canBeEmpty) {
this.canBeEmpty = canBeEmpty;
return (VCB) this;
}
#SuppressWarnings("unchecked")
public VCB setDefault() {
this.canBeNull = false;
this.canBeEmpty = false;
return (VCB) this;
}
public abstract VC build();
}
}
Subclass:
1 - Removed lombok AllArgsConstructor.
2 - Declared the AllArgsConstructor and passed the variables to superclass constructor.
3 - Access to superclass variables using super keyword.
#Builder
public class StringValidatorConfig extends CommonValidatorConfig<StringValidatorConfig> {
private StringValidatorConfig(boolean canBeNull, boolean canBeEmpty) {
super(canBeNull, canBeEmpty);
}
public static class StringValidatorConfigBuilder extends CommonValidatorConfigBuilder<StringValidatorConfig, StringValidatorConfigBuilder> {
#Override
public StringValidatorConfig build() {
return new StringValidatorConfig(super.canBeNull, super.canBeEmpty);
}
}
}
Related
I have this Interface:
public interface Test<T> {
default Class<?> getT() {
return T.getClass(); < --error
}
}
next i have a class that implements it:
static class ItemService implements Test<Item>{
}
And i want to get the 'Item' class from the 'ItemService' class
static ItemService service = new ItemService();
private static void k() {
System.out.println(service.getT());
}
Now one way to do it is this:
public interface Test<T> {
default Class<?> getT() {
return Type.type;
}
class Type {
public static Class<?> type;
}
}
Service:
static class ItemService implements Test<Item> {
public ItemService() {
Type.type = Item.class;
}
}
And it works fine but there is a problem,
When another class implement the interface:
static class OrderService implements Test<Order> {
public OrderService() {
Type.type = Order.class;
}
}
And i try:
static ItemService service = new ItemService();
static OrderService orderservice = new OrderService();
private static void k() {
System.out.println(service.getT());
}
I get the Order class and not the Item class
How can i make it work?
Classes inside interfaces are static, You can remove the default from the function and every class will need to implement this. example:
public interface Test<T> {
public Class<T> getT();
}
static class ItemService implements Test<Item> {
public Class<Item> getT() {return Item.class;}
}
static class OrderService implements Test<Order>{
public Class<Order> getT() {return Order.class;}
}
An alternative could be an abstract class.
public interface Test<T> {
public Class<T> getT();
}
abstract class AbstractTest<T> implements Test<T> {
private final Class<T> type;
AbstractItemService(Class<T> type) { this.type = type }
public Class<T> getT() {return type;}
}
class ItemService extends AbstractTest<Item> {
ItemService() { super(Item.class); }
// implement other things
}
class OrderService extends AbstractTest<Order>{
OrderService() { super(Order.class); }
// implement other things
}
Here is another option, if your implementation has an instance of T.
interface Test<T>{
T getT();
default Class<?> getClassOfT(){
return getT().getClass();
}
}
I can't quite comprehend how to best go about implementing a Builder pattern for the following generics hierarchy.
Base class,
#lombok.Data
public class Node<T> {
private T data;
private String source;
}
Child class,
#lombok.Data
public class MyNode extends Node<MyNode> {
private String firstDummy;
private String secondDummy;
}
Is there anyway to apply an anonymous builder class to the parent and extend it in the child class ?
Updated
If i have an anonymous builder like so for the Parent,
public class Node<T> {
private T data;
private final String source;
public static abstract class Builder<S extends Node> {
private String source;
public Builder<S> withSource(String source) {
this.source = source;
return this;
}
public abstract S build();
}
public static Builder<?> builder() {
return new Builder<Node>() {
#Override
public Node build() {
return new Node(this);
}
};
}
protected Node(Builder<?> builder) {
this.source = builder.source;
}
}
How do I then implement the builder for T in Node class ?
If you want to practice im implementing builders, then yes, you can implement them. The hint of #nixgadget is good.
But if you just need a builder, add an annotation #Builder and Lombok will do that for you.
I am having two java class as below,
public class Class1{
private Object actionObject;
public Object getActionObject() {
return actionObject;
}
public void setActionObject(Object actionObject) {
this.actionObject = actionObject;
}
}
Second class
public class Class2 {
private Long id;
private int idver;
private int valueDate;
}
There are two statement as below,
Class1 deserializedValue = (Class1) event.getDeserializedValue();
Class2.class.isAssignableFrom(deserializedValue.getActionObject().getClass());
I want to mock the second statement
Class2.class.isAssignableFrom(deserializedValue.getActionObject().getClass());
how can i do this?
For testing purposes you can use a strategy pattern. You just need an interface or an abstract class with two different implementations. One of them is the mock implementation, something like this:
public interface EventStrategy {
// More methods...
boolean isAssignableFrom(final Object object);
}
public class MyEvent implements EventStrategy {
public boolean isAssignableFrom(final Object object) {
return Class2.class.isAssignableFrom(object.getClass());
}
}
public class MockEvent implements EventStrategy {
public boolean isAssignableFrom(final Object object) {
return true;
}
}
#Entity
#Inheritance(strategy = InheritanceType.JOINED)
public class A{
private long id;
}
#Entity
public class B extends A{
private String bProperty;
}
#Entity
public class C extends A{
private String cProperty;
}
#Entity
public class Person{
#OneToMany
private Set<A> a;
}
when I use person.getVehicles
How can I know the A is B or C?
I'm using instanceof to check and cast it to get bProperty or cProperty.
Is there any other better way?
The only safe way is to use a polymorphic method. Even instanceof will not work because the instance might actually be a proxy, i.e. a subclass of A that is neither a B or a C, but delegates to a B or a C.
public class A{
private long id;
public abstract boolean isB();
public abstract boolean isC();
public abstract String getBProperty();
public abstract String getCProperty();
}
public class B extends A{
private String bProperty;
public boolean isB() {
return true;
}
public boolean isC() {
return false;
}
public String getBProperty() {
return bProperty;
}
public String getCProperty() {
throw new IllegalStateException("I'm not a C");
}
}
To be cleaner, try using the visitor pattern. I've written a blog post about it. It's in French, but it should be easily translatable.
I have the following simple jaxB class that takes generic type E
#XmlAccessorType(XmlAccessType.FIELD)
#XmlTransient
#XmlRootElement(name = "searchResponseBase")
public abstract class SearchResponseBase<E>{
#XmlElement(type=NameSearchResults.class)
protected E searchResults;
public E getSearchResults()
{
return searchResults;
}
public void setSearchResults(E mSearchResults)
{
this.searchResults = mSearchResults;
}
}
I need to remove the reference to NameSearchResults #XmlElement(type=NameSearchResults.class) to make the base actually generic, but if I do I get the error.
error
[com.sun.istack.internal.SAXException2: class au.test.nameSearch.NameSearchResults nor any of its super class is known to this context.
javax.xml.bind.JAXBException: class au.test.nameSearch.NameSearchResults nor any of its super class is known to this context.]
This is an example of a class that extends it
extended class
#SuppressWarnings("javadoc")
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {
"searchRequest",
"searchResults"
})
#XmlRootElement(name = "searchResponse")
public class SearchResponse extends SearchResponseBase<NameSearchResults> {
#XmlElement(required = true)
protected SearchRequest searchRequest;
public SearchRequest getSearchRequest() {
return searchRequest;
}
public void setSearchRequest(SearchRequest value) {
this.searchRequest = value;
}
}
How do i make the base class actually generic?
preferably i would like my extended class to work in the format SearchResponse<E> extends SearchResponseBase<E> and use it as a generic type too.
if i do as paul suggested i can get teh class to:
#XmlRootElement(name = "searchResponse")
public class SearchResponse<E extends NameSearchResults> extends SearchResponseBase<E> {
#XmlElement(required = true)
protected SearchRequest searchRequest;
protected E searchResults;
public SearchRequest getSearchRequest() {
return searchRequest;
}
public void setSearchRequest(SearchRequest value) {
this.searchRequest = value;
}
#Override
public E getSearchResults() {
return searchResults;
}
#Override
public void setSearchResults(E mSearchResults) {
this.searchResults = mSearchResults;
}
}
is there a way i can push the NameSearchResults out of this <E extends NameSearchResults>?
Thanks to #PaulBellora for the help, the base and extend class will both become abstract then haveing a Name implimentation, like this:
Base
#XmlRootElement(name = "searchResponseBase")
public abstract class SearchResponseBase<E>{
public abstract E getSearchResults();
public abstract void setSearchResults(E mSearchResults);
}
Extended Base
#XmlRootElement(name = "searchResponse")
public abstract class SearchResponse<E> extends SearchResponseBase<E>{
public abstract SearchRequest getSearchRequest();
public abstract void setSearchRequest(SearchRequest value);
}
Name Implimentation
#XmlRootElement(name = "nameSearchResponse")
public class NameSearchResponse extends SearchResponse<NameSearchResults>{
#XmlElement(required = true)
protected SearchRequest searchRequest;
protected NameSearchResults searchResults;
#Override
public NameSearchResults getSearchResults() {
return searchResults;
}
#Override
public void setSearchResults(NameSearchResults mSearchResults) {
this.searchResults = mSearchResults;
}
#Override
public SearchRequest getSearchRequest() {
return searchRequest;
}
#Override
public void setSearchRequest(SearchRequest value) {
this.searchRequest = value;
}
}
I'm unfamiliar with JAXB, but you could try making getSearchResults and setSearchResults abstract methods, and implement them only when E was resolved. For example:
//annotations ommitted
public abstract class SearchResponseBase<E>{
public abstract E getSearchResults();
public abstract void setSearchResults(E mSearchResults);
}
//annotations ommitted
public class SearchResponse extends SearchResponseBase<NameSearchResults> {
#XmlElement(type=NameSearchResults.class)
protected NameSearchResults searchResults;
#Override
public final NameSearchResults getSearchResults() {
return searchResults;
}
#Override
public final void setSearchResults(NameSearchResults mSearchResults) {
this.searchResults = mSearchResults;
}
...
}