Importing Map Keys By Interface - java

Let's say I have a class with a hashmap data structure:
import java.util.HashMap;
import java.util.Map;
import org.openqa.selenium.By;
public abstract class Data {
protected Map<String, By> identifiers = new HashMap<>();
public By getSelector(String key) {
return identifiers.get(key);
}
}
3 subclasses which inherit it:
public class DataSpecific1 extends Data {
}
public class DataSpecific2 extends Data implements KeysForDataSpecific23 {
}
public class DataSpecific3 extends Data implements KeysForDataSpecific23 {
}
Now I want to define an interface which adds hashmap keys to only 2 of these subclasses:
import org.openqa.selenium.By;
public interface KeysForDataSpecific23 {
identifiers.put("key", By.cssSelector("#something"));
}
Obviously, this will cause a compile error since the interface can not inherit from the Data class and the variable identifiers is not defined.
Any way of doing it without redundancy such as adding the put() line in both affected classes?

Nowadays, You have facility in java 8 to have default method in interface ,
With this you can do as follows:
public interface KeysForDataSpecific23 {
default void setKeys(){
identifiers.put("key", By.cssSelector("something"));
}
}
default methods can give inception behavior to interfaces.

You can't, using interfaces.
You can do this, though:
public abstract class KeysForDataSpecific23 extends Data {
protected KeysForDataSpecific23() {
identifiers.put("key", By.cssSelector("something"));
}
}
public class DataSpecific2 extends KeysForDataSpecific23 {
}
public class DataSpecific3 extends KeysForDataSpecific23 {
}

Related

Why class name is same as class used in import statement

Below snippet of code is from ITDIAgentException.java file
Can some one help me understand "why class name is same as class used in import statement"(ITDIAgentException)
import com.ibm.di.entry.Entry;
import com.ibm.di.exception.ITDIAgentException;
public class ITDIAgentException extends Exception {
private Entry entry = null;
public ITDIAgentException(String paramString) { super(paramString); }
public Entry getEntry() { return this.entry; }
public void setEntry(Entry paramEntry) { this.entry = paramEntry; }
}
EDIT
You have ITDIAgentException twice: Once in the import statement, and once in the class definition. You are not allowed to have both (would create a namespace clash in the code), but you can access com.ibm.di.exception.ITDIAgentException (assuming that it is different from the class you are creating) by using the full package and class name.
import com.ibm.di.exception.ITDIAgentException;
public class ITDIAgentException extends Exception {

How a nested default interface differs from a nested protected interface?

What are the differences between nested default and nested protected interfaces in Java? Why nested protected interfaces are even allowed?
Test.java
public class Test {
// not implementable outside of current package
interface NestedDefaultInterface {
}
// not implementable outside of current package?
protected interface NestedProtectedIface {
}
}
// both interfaces can be implemented
class Best implements Test.NestedProtectedIface, Test.NestedDefaultInterface {
}
MyClass.java
class AClass implements Test.NestedProtectedIface { //Error
}
class AnotherClass implements Test.NestedDefaultInterface { //Error
}
class OneMoreClass extends Test implements Test.NestedProtectedIface { //Error
}
To show the visual difference:
package com.one
public class Test {
// not implementable outside of current package
interface NestedDefaultInterface {
}
// implementable in child classes outside of package
protected interface NestedProtectedIface {
}
}
Outside of the package:
package com.two
class SubTest extends Test {
public void testProtected() {
NestedProtectedIface npi = new NestedProtectedIface () {
// implementation
};
}
public void testDefault() {
// Won't compile!
// NestedDefaultInterface ndi = new NestedDefaultInterface() {
// };
}
}
The confusion here is about visibility.
When you extending a class you will get access to all protected parent properties from this reference.
For default access modifier it will not work outside of the package.
The most popular real-world example of nested interface is Map.Entry<K,V> of java.util.Map.
Each implementation of Map provides its own Entry<K,V> implementation. (Node<K,V> in HashMap, Entry<K,V> in TreeMap and etc.)

How can a java method take an argument that extends a generic type

I'm trying to implement a small MongoDB application as a jar file which can be used from a series of other applications. (Running Java 6)
The purpose is to have a class that handles and contains DBCollection, MongoDatabase and MongoClient.
This superclass can be extended by these other applications and the MongoDB used from these. I would also like the other applications to implement an interface which contains 1 insertIntoDB() method. This insertIntoDB() method should take 1 parameter which would be another subclass and herein is my problem. How can the interface specify an extension of a generic type so that each implementation returns the extended types ?
Below is a bit further explanation:
class AsuperClass implements Ainterface {
MongoClient aMongoClient
MongoDatabase aMongoDatabase
initMongoDb() {
//doStuff
}
}
class AsuperPojo {
int propA
String propB
}
interface Ainterface {
void insertToDb(AsuperPojo);
}
class SubClass1 implements Ainterface extends AsuperClass{
#Override
public void insertToDb(SpecialSubClass1Pojo aSpecialSubClass1Pojo) {
//doStuff
}
}
class SpecialSubClass1Pojo() {
int propA
String propB
}
class SubClass2 implements Ainterface extends AsuperClass{
#Override
public void insertToDb(SpecialSubClass2Pojo aSpecialSubClass2Pojo) {
//doStuff
}
}
class SpecialSubClass2Pojo() {
int propA
String propB
}
Maybe there's a completely different way of doing this?
If I did understand well, you are looking for this:
interface Ainterface<T extends AsuperPojo> {
void insertToDb(T foo);
}
then use:
class SubClass2 implements Ainterface<SpecialSubClass2Pojo>
Some reading: https://docs.oracle.com/javase/tutorial/java/generics/

avoid raw generic type in inheritance/delegation structure

My problem is quite complex and hard to explain, so I built a smaller example. It's still complex, but let me try my best...
You can download the full example here: https://mega.co.nz/#!400lSbqa!NoyflWYk6uaQToVDEwXyn22Bdcn_6GdTxB6dPUfU5FU
I recommend importing this into your favourite IDE and playing around.
Imagine you are programming a multiplayer game. It is supposed to have a world with entities. The code should be split into server, client, and shared stuff.
Each of my entities consist of 3 files:
the base, which contains shared code and resources like the name
the clientside, which derive the base and contain rendering etc.
the serverside, which also derive the base and contain network events etc.
Because I can only derive from one class but want my client/server entities to have some shared code too, I tried it with a delegation-style structure. Let's name the actual entity [default], mark interfaces with *'s and extends / implements with <-
- *BaseEntity*
- [DefaultBaseEntity] <- *BaseEntity*
- *ClientEntity* <- *BaseEntity*
- [DefaultClientEntity] <- [DefaultBaseEntity], *ClientEntity*
- *ServerEntity* <- *BaseEntity*
- [DefaultServerEntity] <- [DefaultBaseEntity], *ServerEntity*
This way, I can also duck-typing-access The server/client specific implementations plus the base implementations with only holding ClientEntity/ServerEntity.
Now I want to program a world containing those entities. The world's code shall also be split into three parts and be generic to either contain server or client entities.
package base;
import java.util.ArrayList;
import java.util.List;
public abstract class BaseWorld<E extends BaseEntity> {
private List<E> entities;
public BaseWorld() {
entities = new ArrayList<>();
}
public void addEntity(E entity) {
entity.setWorld(this);
entities.add(entity);
}
public List<E> getEntities() {
return entities;
}
public void doStuffWithBuilding(E entity) {
entity.doBasestuff();
}
}
package client;
import base.BaseWorld;
public class ClientWorld extends BaseWorld<ClientEntity>{
}
package server;
import base.BaseWorld;
public class ServerWorld extends BaseWorld<ServerEntity> {
}
As you see, I am giving my entities a backreference to the world they are in. And this contains the actual problem.
Here's a look into the corresponding entity code:
package base;
public class DefaultBaseEntity implements BaseEntity {
private BaseWorld world;
#Override
public void doBasestuff() {
System.out.println("I am base entity");
}
#Override
public void setWorld(BaseWorld world) {
this.world = world;
}
#Override
public BaseWorld getWorld() {
return world;
}
}
Now this works, but BaseWorld is a raw type. Obviously, every IDE starts to complain. I also do not want to suppress warnings.
I cannot use wildcard types like BaseWorld<? extends BaseEntity> either, because they produce compile errors, when I call world methods like doStuffWithBuilding():
package client;
import base.DefaultBaseEntity;
public class DefaultClientEntity extends DefaultBaseEntity implements ClientEntity {
#Override
public void doClientstuff() {
System.out.println("I am client");
getWorld().doStuffWithBuilding(this);
}
}
The method doStuffWithBuilding(capture#1-of ? extends BaseEntity) in
the type BaseWorld is not
applicable for the arguments (DefaultClientEntity)
Is there any solution to this? I tried removing the set/getWorld() from the base interface and adding it to client and server, but that was very clunky and causes a lot of repitition because of the delegation.
You can probably get around this by parameterizing DefaultBaseEntity:
public class DefaultBaseEntity <E extends BaseEntity>
implements BaseEntity<E> {
private BaseWorld<E> world;
// ...
}
public class DefaultClientEntity extends DefaultBaseEntity<ClientEntity>
implements ClientEntity {
// ...
}
Observe that DefaultClientEntity does not need to be parameterized (at least not for this purpose), even though its superclass is.
Update:
Furthermore, you can perform analogous parameterization with your interfaces:
interface BaseEntity <E extends BaseEntity> {
public void setWorld(BaseWorld<E> world);
// ...
}
interface ClientEntity extends BaseEntity<ClientEntity> {
// ...
}
The example DefaultBaseEntity code above is updated to implement that generic BaseEntity interface.
You will have to put the right type parameters everywhere:
public interface BaseEntity<E extends BaseEntity> {
public void doBasestuff();
public void setWorld(BaseWorld<E> world);
public BaseWorld<E> getWorld();
}
public interface ClientEntity<E extends BaseEntity> extends BaseEntity<E> { ... }
public class DefaultBaseEntity<E extends BaseEntity> implements BaseEntity<E> {
private BaseWorld<E> world;
#Override
public void doBasestuff() {
System.out.println("I am base entity");
}
#Override
public void setWorld(BaseWorld<E> world) {
this.world = world;
}
#Override
public BaseWorld<E> getWorld() {
return world;
}
}
public class DefaultClientEntity extends DefaultBaseEntity<DefaultClientEntity>
implements ClientEntity<DefaultClientEntity> { ... }

Tangled in generics

I have classes A, B with B extends A
I have interface defined as
public interface MyProcessor<EVENT> {
void processEvent(EVENT event);
}
I have two implementations
public class EventAProcessor implements EventProcessor<A> {
#Override
public void processEvent(A a) {
}
public class EventBProcessor implements EventProcessor<B> {
#Override
public void processEvent(B b) {
}
there is common processing so I decided to extend BProcessor from Aprocessor
public class EventBProcessor extends EventAProcessor implements EventProcessor<B> {
}
This is where it fails with the message
MyProcessor cannot be inherited with different arguments: <A> and <B>
I have other solutions to workaround my problem, but just wondering, how to get this working.
Don't make EventBProcessor extend EventAProcessor as it's not an is-a relationship. Reuse the functions you need either by pulling them into a common abstract class, or in a separate helper class that you reuse by composition. It's not always the best option to reuse through inheritance.
You should introduce an abstract generic class:
public abstract class AbstractEventProcessor<EVENT>
implements EventProcessor<EVENT> {
// Put your common logic here
}
Your other classes will then inherit common functionality as such:
public class EventAProcessor extends AbstractEventProcessor<A> {}
public class EventBProcessor extends AbstractEventProcessor<B> {}
This doesn't necessarily have to do with generics. It's a general way to approch polymorphism in object-oriented programming.
If you want to reuse code through inheritance, the following should be OK:
public abstract AbstractEventAProcessor<T extends A> implements EventProcessor<T> {
// common methods
}
public class EventAProcessor extends AbstractEventAProcessor<A> {
#Override
public void processEvent(A a) { ... }
}
public class EventBProcessor extends AbstractEventAProcessor<B> {
#Override
public void processEvent(B b) { ... }
}
I don't see how the interface has anything to do with either of your implementations. Neither of them implements the MyProcessor interface.
You also don't show any hierarchy for the Event class. What makes you think you can have different Event types with this arrangement?
Here's how I might do it:
public interface Event {
String getName();
}
public interface EventProcessor<T extends Event> {
void process(T event);
}
You don't need different EventProcessor implementations this way - the generic should be able to differentiate between different Event types. You'll only need a custom implementation if the process() method needs to change by type. You might way to think about a Visitor pattern if it does.
Add a shared "common" generic ancestor that requires A or a subclass thereof.
public abstract class ACommonProcessor<AEvent extends A> implements MyProcessor<AEvent> {
...
// shared code goes here
}
public class EventBProcessor extends ACommonProcessor<B> {
...
// B-specific code goes here
}
public class EventAProcessor extends ACommonProcessor<A> {
...
// etc
}

Categories