Generics, statics, reflection || wie baue ich eine static getManager mit generics &

toneempire

Grünschnabel
Servus,

ich versuche gerade mir eine abstrakte Klasse zu bauen von der alle meine POJOs erben sollen. Anhand dieser abstrakten Klasse (AbstractBean) soll jedes POJO seinen eigenen Manager (für laden/speichern etc) laden können.

Tja, soweit so gut. Bisweilen tuts schon, nur wird a) für jedes POJO der Manager separat erzeugt und b) wäre es viel cooler wenn die getManager static wäre, so das ich nicht immer eine Instanz vorher haben muss.

Ich zeig mal was ich meine

Java:
/** die abstrakte Bean **/

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;


public abstract class AbstractBean<M> implements IBean {

	private M			manager			= null;
	private Class<M>	managerClass	= null;

	@SuppressWarnings("unchecked")
	public M getManager() {
		if (managerClass == null) {
			try {
				Type[] t = ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments();
				if (t[0] instanceof Class) {
					this.managerClass = (Class<M>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
				} else if( t[0] instanceof Type) {
					ParameterizedType pt = (ParameterizedType) t[0];
					managerClass = (Class<M>) pt.getRawType();
				} else {
					throw new RuntimeException("could not resolve manager class");
				}
				Constructor<?> c = 
						managerClass.getConstructor(new Class<?>[0]);
				manager = (M) c.newInstance(new Object[0]);
			} catch (SecurityException ex) {
				ex.printStackTrace();
			} catch (IllegalArgumentException ex) {
				ex.printStackTrace();
			} catch (NoSuchMethodException ex) {
				ex.printStackTrace();
			} catch (InstantiationException ex) {
				ex.printStackTrace();
			} catch (IllegalAccessException ex) {
				ex.printStackTrace();
			} catch (InvocationTargetException ex) {
				ex.printStackTrace();
			}
		}
		return manager;
	}
	
	/**
	
	Im entfernten Sinne stelle ich mir sowas vor

	public static M getManagerObject () {

		return null;
	}
	
	**/

}
Java:
/** der abstrakte Manager **/


import java.lang.reflect.ParameterizedType;
import java.util.List;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.hibernate.Session;

import de.wac.mcp.storage.hibernate.HibernateStorage;

public abstract class AbstractManager<B> {

	protected static Log		logger	= LogFactory.getLog(AbstractManager.class);

	protected HibernateStorage	storage	= null;
	private Class<B>			persistentClass;

	public boolean save(B bean) {
		return storage.saveOrUpdateObject(bean);
	}

	public boolean save(Session session, B bean) {
		return storage.saveOrUpdateObject(session, bean);
	}

	public boolean update(B bean) {
		return storage.saveOrUpdateObject(bean);
	}

	public boolean update(Session session, B bean) {
		return storage.saveOrUpdateObject(session, bean);
	}

	public boolean delete(B bean) {
		return storage.deleteObject(bean);
	}

	public boolean delete(Session session, B bean) {
		return storage.deleteObject(session, bean);
	}

	public B load(Long id) {
		if (id != null && id > 0) {
			return storage.getObject(getPersistentClass(), id);
		}
		return null;
	}

	public List<B> loadAll() {
		return storage.getObjectList(getPersistentClass());
	}

	@SuppressWarnings("unchecked")
	private Class<B> getPersistentClass() {
		if (persistentClass == null)
			this.persistentClass = (Class<B>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		return persistentClass;
	}
}
Java:
public class TestBean extends AbstractBean<TestManager>{

	public long getId() {
		return -1;
	}
	
}
Java:
public class TestManager extends AbstractManager<TestBean> {

	public TestManager() {
		super();
		storage = HibernateStorage.getInstance();
	}
	
	public java.util.List<TestBean> getTestBeansWhereBla() {
	  // do blabla
	  return null;
	}
	
}
Java:
public class Test {

	public static void main(String [] arg) {
		
		TestBean tb = new TestBean();
		// do something with TestBean, fillit
		tb.getManager().save(tb);
		
		// geht
		TestBean loader = new TestBean().getManager().load(1);
		
		// wäre schöööner, wäre mein Wunsch.
		TestBean loader2 = TestBean.getManager().load(1);
	}
}


Naja, zumindest soll mir der zurückgegebene Manager <M> (wie im Wunschbeispiel verwendet bei "TestBean loader2" ) all die Funktionen bieten die der entsprechende via generics erzeugte Manager besitzt.


Hoffentlich kann mir da mal jemand weiter helfen! ;-)


Gruß


Tom
 
Zuletzt bearbeitet von einem Moderator:
Hi,
ersteinmal verwende bitte für Javacode auch die Java-Code-Tags (siehe meine Signatur). Danke.

Dein Wunsch wird leider nicht in Erfüllung gehen. Das hat folgenden Hintergrund. Eine abstract Klasse kann zwar static-Methoden haben, diese sind allerdings Klassen- und nicht Objektgebunden. D.h. dass bei dem Vererben des AbstractManager-Objekts nur die Objektgebundenen Methoden (alle nicht static) vererbt werden.

Gruß

Fabio
 
Ja, sorry. Habe beim Editor hier nur die php Tags gefunden.

Bzgl. der static gebe ich dir Recht.

Meine Idee wäre halt das man einen Manager einmal läd, diesen in eine static Map packt um ihn zu cachen und die eigentliche

Java:
public static M getManagerObject() {
  return managerCache.get(implementingBeanName);
}

greift dann auf den Cache zu.

Zum Teil ist es mir auch gelungen. Aber es wird dann immer nur auf einen AbstractManager<?> hinauslaufen. Und das möchte ich nicht. Schön wäre wenn ich dort die entsprechende Implementierung ohne Casten bekommen würde.

Naja, das wäre die Idee!
 
Also um die Manager zu chachen mussst du das Erzeugen der static Insatnz in die Klasse packen, die von AbstractManager abgeleitet wird, bzw. die "End"-Managerklasse. Wenn du das nicht schon machst jetzt.
Allerdings solltest du beachten, dass du dadurch mehrere Hibernate-Sessions offen hast. (pro Manager eine)

Ich habe damit jetzt selber mal rumexperimentiert, da ich zu geben muss, dass ich bisher selber noch fast gar nichts mit generics gemacht habe.

Der Cache an sich:
Java:
/**
 * @author FabioH
 */
public final class Cache
{
	private static final Map<Class<?>, Cacheable> cache = new HashMap<Class<?>, Cacheable>();
	
	private Cache() {
	}

	/**
	 * @param cacheableObject
	 */
	public static void add(Cacheable cacheableObject) {
		cache.put(cacheableObject.getClass(), cacheableObject);
	}
	
	/**
	 * @param <T> 
	 * @param c
	 */
	public static <T> void remove(Class<T> c) {
		cache.remove(c);
	}
	
	/**
	 * @param <T>
	 * @param c
	 * @return
	 */
	public static <T> T get(Class<T> c) {
		return (T) cache.get(c); 
	}
}

und das Cacheable Interface:
Java:
/**
 * @author FabioH
 */
public interface Cacheable
{
}

Gruß

Fabio
 
Zuletzt bearbeitet:
Hi!

Hm hm hm, so richtig glücklich bin ich noch nicht, glaub ich. Muss selber noch ein bisschen rumprobieren.

Danke für den Tipp!

Gruß,

Tom
 
Zurück