2013-08-27 3 views
1

그래, 이건 설명하기가 상당히 어렵습니다. 난 내 최선을 다할 것입니다.Java Reflection을 사용한 이벤트 처리

@ EventHandler를 사용하여 이벤트 핸들러를 void 처리 할 수있는 Bukkit Event System에서 영감을 얻었습니다.

예 :

@EventHandler 
public void aRandomName(PlayerMoveEvent ev) { 

} 

당신이 볼 수 있듯이, 메소드의 이름은 중요하지 않습니다. 어떤 이벤트가 전달되는지는 이벤트 인수 유형에 의해 결정됩니다.

모든 이벤트는 Event 클래스를 확장합니다. 한 가지를 제외하고는 작동한다고 생각되는 코드를 만들었습니다.

public List<Object> eventContainers; 

public void fireEvent(Event e) { 

    Method[] methods; 

    for (Object o : eventContainers) { 
     Object[] classes = o.getClass().getClasses(); 

     for (Object clss : classes) { 
      methods = clss.getClass().getMethods(); 
      for (Method m : methods) { 
       if (m.getAnnotation(EventHandler.class) != null) { 
        try { 
         Class[] requiredTypes = m.getParameterTypes(); 
         for(Class cl : requiredTypes) { 
          if(e.equals(cl)) { 
           m.invoke(clss, e); 
          } 
         } 

        } catch (IllegalAccessException ex) { 
        } catch (IllegalArgumentException ex) { 
        } catch (InvocationTargetException ex) { 
        } 
       } 
      } 
     } 
    } 
} 

내 코드가 무엇을 : 루프가 eventContainers의 모든 클래스를 통해 @EventHandler 주석이 있고 그 방법에 지정된 이벤트를 보내는 방법을 찾습니다. 그러나 fireEvent (Event e)에서 주어진 이벤트가 어떤 종류의 이벤트인지 확인한 다음 해당 종류의 이벤트 매개 변수를 필요로하는 메서드를 살펴보고 싶습니다. 내가 어떻게 그럴 수 있니? 나는 그것을 이해한다

Class[] requiredTypes = m.getParameterTypes(); 
for(Class cl : requiredTypes) { 
    if(e.equals(cl)) { 
    m.invoke(clss, e); 
    } 
} 

는 작용하지 않을 것이다.

궁극적으로 저는 플러그인에 이벤트를 전달할 수 있기를 바랍니다. 이처럼 모든 플러그인과 당신은 질문이있는 경우

@EventHandler 
public void aVoid(PlayerMoveEvent e) { 
//stuff 
} 

이 플러그인로 전송됩니다

EventManager.fireEvent(new PlayerMoveEvent(player)); 

, 나는 더 나은 설명하려고합니다. 도와 주셔서 미리 감사드립니다.

답변

0

코드는 Class (Event의 인스턴스의 클래스)의 인스턴스와 Event의 인스턴스를 비교하는, e.equals(cl)를 사용 -이 true를 반환하지 않습니다. 당신이 대신하고 싶은 것은 :

if(e.getClass().equals(cl)) { 
    m.invoke(clss, e); 
} 

또는, 당신은 클래스의 모든 서브 클래스를 처리 할 수 ​​@EventHandler 주석 방법을 원한다면 그들의 방법 서명을 정의 (즉,handle(Event e) 같은 방법은 다음 원하는) PlayerMoveEvents뿐만 아니라 다른 모든 이벤트를 호출 할 것이다 :

if(cl.isAssignableFrom(e.getClass())) { 
    m.invoke(clss, e); 
} 

자세한 내용은 Class Javadoc here를 참조하십시오.

코드에 몇 가지 다른 문제가 있다고 생각합니다. 예를 들어 Method.invoke@EventHandler이라는 주석이있는 메소드가 포함 된 클래스의 인스턴스와 함께 호출해야합니다. 그것은 당신의 코드에서 약간 불분명하지만, 나는이 따라서 있어야한다고 생각 : 당신이 o의 클래스에 정의 된 클래스 반복되는 o.getClass().getClasses()를 호출하여 또한

m.invoke(o, e); 

, - 당신은 아마 반복 할 즉, 직접 o의 클래스의 방법 :

for (Method m : o.getClass().getMethods()) { 
    if (m.getAnnotation(EventHandler.class) != null) { 
     Class[] requiredTypes = m.getParameterTypes(); 
     if (requiredTypes.length == 1 && requiredTypes[0].isAssignableFrom(e.getClass()) { 
      m.invoke(o, e); 
     } 
    } 
} 
0

당신은 너무, method.getGenericParameterTypes() 사용하여 Method에서 매개 변수 유형을 얻을 수 있습니다 :

m.invoke(clss, m.getGenericParameterTypes()[0].class.cast(e)); 

만약 당신이 원하는 경우에 확실하지. EventHandler 주석 방법을 가정

+0

코드 조각을 보면 이벤트 e를 메소드에 필요한 매개 변수로 캐스팅하려고 시도하는 것처럼 보입니다. 그것이 할 수없는 경우에 보내지 않을 것인가? (예외적으로 잡기) 나는 이것이 내가 찾고있는 것이라고 생각한다. 고마워! – Limnic

+0

그것이 내가하는 일이며, 필요한 매개 변수로 이벤트를 캐스팅하십시오. 예외 처리를 위해 일반 try/catch 블록을 사용할 수 있습니다. InvocationTargetException, IllegalAccessException, ClassCastException을 참조하십시오. –

0

는 하나의 매개 변수 만에게 내가 어떤 예외 처리를 포함하지했습니다

Method[] methods = YourClass.class.getDeclaredMethods(); 
Object yourInstance = null; // get it 
Event e = null; // get it 
for (Method method : methods) { 
    EventHandler handler = method.getAnnotation(EventHandler.class); 
    if (handler != null) { 
     Class<?>[] parameterTypes = method.getParameterTypes(); 
     // you're going to need different logic if you have more than one parameter 
     if (parameterTypes.length == 1 && parameterTypes[0].isAssignableFrom(e.getClass())) { 
      method.invoke(yourInstance, e); 
     } 
    } 
} 

있습니다.

이벤트 처리기 후보 클래스의 모든 메서드를 가져 와서 반복합니다. 메소드에 @EventHandler 주석이 있으면 매개 변수 유형 목록을 가져옵니다. 하나의 매개 변수 만 있고 해당 유형을 이벤트 유형 e.getClass()에서 할당 할 수 있으면 해당 이벤트를 이벤트에서 전달하십시오.

0

는 지금 작업 이벤트 시스템에 코드를 수정 한 !!!!!! : D 감사합니다 너무 많은 andersschuller!

public void fireEvent(Event e) { 

    Method[] methods; 

    for (Object o : eventContainers) { 
     methods = o.getClass().getMethods(); 
     for (Method m : methods) { 
      if (m.getAnnotation(EventHandler.class) != null) { 
       try { 

        if (m.getParameterTypes()[0].isAssignableFrom(e.getClass())) { 
         m.invoke(o, e); 
        } 
       } catch (IllegalAccessException ex) { 
       } catch (IllegalArgumentException ex) { 
       } catch (InvocationTargetException ex) { 
       } 
      } 
     } 
    } 
} 

나는 모두에게 감사의 말을 전했다.

관련 문제