2014-10-14 19 views
19

starałem się wywołać custom url z mojego programu Java, stąd kiedyś coś takiego:Rejestrowanie i przy użyciu protokołu zwyczaj java.net.URL

URL myURL; 
try { 
    myURL = new URL("CustomURI:"); 
    URLConnection myURLConnection = myURL.openConnection(); 
    myURLConnection.connect(); 
} catch (Exception e) { 
    e.printStackTrace(); 
} 

Dostałem poniższy wyjątek:

java.net.MalformedURLException: nieznany protokół: CustomURI na java.net.URL (Unknown Source) na java.net.URL (Unknown Source) na java.net.URL (Unknown Source) w... com.demo.TestDemo.main (TestDemo.jav a: 14)

Gdybym wywołać URI z przeglądarki to działa zgodnie z oczekiwaniami, ale gdy próbuję wywołać go z Java Program następnie otrzymuję powyższy wyjątek.

EDIT:

Poniżej przedstawiono kroki próbowałem (brakuje mi czegoś na pewno, proszę dać mi znać o tym):

Krok 1: Dodawanie niestandardowego URI w java.protocol.handler.pkgs

Krok 2: Wyzwalanie Custom URI z URL

Kod:

public class CustomURI { 

public static void main(String[] args) { 

    try { 
     add("CustomURI:"); 
     URL uri = new URL("CustomURI:"); 
     URLConnection uc = uri.openConnection();    
     uc.connect(); 
    } catch (Exception e) { 
     e.printStackTrace(); 
    } 

} 

public static void add(String handlerPackage){ 

    final String key = "java.protocol.handler.pkgs"; 

    String newValue = handlerPackage; 
    if (System.getProperty(key) != null) 
    { 
     final String previousValue = System.getProperty(key); 
     newValue += "|" + previousValue; 
    } 
    System.setProperty(key, newValue); 
    System.out.println(System.getProperty("java.protocol.handler.pkgs")); 

} 

} 

Kiedy uruchomić ten kod, otrzymuję CustomURI: drukowane w mojej konsoli (z metody Add), ale następnie otrzymuję ten wyjątek, gdy URL jest zainicjowany z CustomURI: jako konstruktor:

Exception in thread "main" java.lang.StackOverflowError 
at java.lang.Class.forName0(Native Method) 
at java.lang.Class.forName(Unknown Source) 
at java.net.URL.getURLStreamHandler(Unknown Source) 
at java.net.URL.<init>(Unknown Source) 
at java.net.URL.<init>(Unknown Source) 
at sun.misc.URLClassPath$FileLoader.getResource(Unknown Source) 
at sun.misc.URLClassPath.getResource(Unknown Source) 
at java.net.URLClassLoader$1.run(Unknown Source) 
at java.security.AccessController.doPrivileged(Native Method) 
at java.net.URLClassLoader.findClass(Unknown Source) 
at java.lang.ClassLoader.loadClass(Unknown Source) 
at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source) 
at java.lang.ClassLoader.loadClass(Unknown Source) 
at java.net.URL.getURLStreamHandler(Unknown Source) 
at java.net.URL.<init>(Unknown Source) 
at java.net.URL.<init>(Unknown Source) 

Proszę doradzić, jak to działa.

+1

Co jest _as expected_ –

+0

'Co oznacza Expected' że zwyczaj URL uruchamia aplikację Zasadniczo ten niestandardowy adres URL jest registr y wpis, który utworzyłem do uruchamiania aplikacji desktopowych. – user182944

+3

Jestem prawie pewien, że będziesz musiał napisać własny "URLStreamHandlerFactory" do obsługi tego protokołu. –

Odpowiedz

44
  1. Tworzenie niestandardowego URLConnection realizację, która wykonuje pracę w connect() metody.

    public class CustomURLConnection extends URLConnection { 
    
        protected CustomURLConnection(URL url) { 
         super(url); 
        } 
    
        @Override 
        public void connect() throws IOException { 
         // Do your job here. As of now it merely prints "Connected!". 
         System.out.println("Connected!"); 
        } 
    
    } 
    

    Nie zapomnij zastąpić i zastosować inne metody, takie jak getInputStream(). Więcej szczegółów na ten temat nie można podać, ponieważ w pytaniu brakuje tych informacji.


  2. Tworzenie niestandardowego URLStreamHandler wdrożenie która zwraca go w openConnection().

    public class CustomURLStreamHandler extends URLStreamHandler { 
    
        @Override 
        protected URLConnection openConnection(URL url) throws IOException { 
         return new CustomURLConnection(url); 
        } 
    
    } 
    

    Nie zapomnij zastąpić i zastosować inne metody, jeśli to konieczne.


  3. Tworzenie niestandardowego URLStreamHandlerFactory która tworzy i zwraca go w oparciu o protokół.

    public class CustomURLStreamHandlerFactory implements URLStreamHandlerFactory { 
    
        @Override 
        public URLStreamHandler createURLStreamHandler(String protocol) { 
         if ("customuri".equals(protocol)) { 
          return new CustomURLStreamHandler(); 
         } 
    
         return null; 
        } 
    
    } 
    

    Należy pamiętać, że protokoły to always małe litery.


  4. Wreszcie zarejestrować go podczas uruchamiania aplikacji poprzez URL#setURLStreamHandlerFactory()

    URL.setURLStreamHandlerFactory(new CustomURLStreamHandlerFactory()); 
    

    nocie że Javadoc wyraźnie mówi, że można go ustawić co najwyżej raz. Jeśli więc zamierzasz obsługiwać wiele niestandardowych protokołów w tej samej aplikacji, musisz wygenerować niestandardową implementację URLStreamHandlerFactory, aby uwzględnić je wszystkie w metodzie createURLStreamHandler().


    Ewentualnie, jeśli nie lubią Prawo Demeter, wrzuć to wszystko razem w anonimowych klas dla kodu minifikacji:

    URL.setURLStreamHandlerFactory(new URLStreamHandlerFactory() { 
        public URLStreamHandler createURLStreamHandler(String protocol) { 
         return "customuri".equals(protocol) ? new URLStreamHandler() { 
          protected URLConnection openConnection(URL url) throws IOException { 
           return new URLConnection(url) { 
            public void connect() throws IOException { 
             System.out.println("Connected!"); 
            } 
           }; 
          } 
         } : null; 
        } 
    }); 
    

    Jeśli jesteś na Java 8 już wymienić funkcjonalny interfejs URLStreamHandlerFactory przez lambda dalszego minifikacji:

    URL.setURLStreamHandlerFactory(protocol -> "customuri".equals(protocol) ? new URLStreamHandler() { 
        protected URLConnection openConnection(URL url) throws IOException { 
         return new URLConnection(url) { 
          public void connect() throws IOException { 
           System.out.println("Connected!"); 
          } 
         }; 
        } 
    } : null); 
    

Teraz można go używać w następujący sposób:

URLConnection connection = new URL("CustomURI:blabla").openConnection(); 
connection.connect(); 
// ... 

Albo z małe litery protokołu co za spec:

URLConnection connection = new URL("customuri:blabla").openConnection(); 
connection.connect(); 
// ... 
+1

Próbowałem tego (szczegóły tutaj http://stackoverflow.com/questions/37528167/how-to-set-source-ip-to-http-request/37532231 # 37532231) Czy możliwe jest dostarczenie implementacji 'getInputStream()' – theHeman

+0

Dla zainteresowanych: https://en.wikipedia.org/wiki/Law_of_Demeter – Matthieu

+1

Czy musimy wywołać 'URL.setURLStreamHandlerFactory()' if umieszczamy wszystkie niezbędne klasy w "pakiecie domyślnym"? (który z nich jest btw?) – Matthieu

1

Zrobiłeś rekurencji/nieskończoną pętlę.

Classloader szukający klasy na różne sposoby.

StackTrace (URLClassPath) jest tak:

  1. ładowania zasobu.
  2. Czy załadowałem każdy protokół? Nie!
  3. Załaduj wszystkie procedury obsługi protokołów, nie mogę znaleźć pliku «your java.protocol.handler.pkgs-package».CustomURI.Handler.
  4. Ta klasa to zasób! Czy załadowałem każdy protokół? Nie!
  5. Załaduj wszystkie procedury obsługi protokołów, nie mogę znaleźć pliku «your java.protocol.handler.pkgs-package».CustomURI.Handler.
  6. Ta klasa to zasób! Czy załadowałem każdy protokół? Nie!
  7. Załaduj wszystkie procedury obsługi protokołów, nie mogę znaleźć pliku «your java.protocol.handler.pkgs-package».CustomURI.Handler.
  8. Ta klasa to zasób! Czy załadowałem każdy protokół? Nie!
  9. Załaduj wszystkie procedury obsługi protokołów, nie mogę znaleźć pliku «your java.protocol.handler.pkgs-package».CustomURI.Handler.
  10. Ta klasa to zasób! Czy załadowałem każdy protokół? Nie!
  11. Załaduj wszystkie procedury obsługi protokołów, nie mogę znaleźć pliku «your java.protocol.handler.pkgs-package».CustomURI.Handler.

    ...... StackOverflowException !!!

1

Jeśli nie chcesz przejąć jeden i tylko URLStreamHandlerFactory, rzeczywiście można użyć ohydne, ale skutecznej konwencji nazewnictwa, aby w sprawie realizacji domyślnej.

Ty koniecznością nazwa klasa URLStreamHandlerHandler, a protokół mapuje jest ostatnim segmentem tego pakietu klasy.

Więc com.foo.myproto.Handler ->myproto:urls, warunkiem dodać swój pakiet com.foo do listy „URL strumień pakietów źródłowych” do odnośnika na nieznanego protokołu. Robisz to poprzez właściwość systemową "java.protocol.handler.pkgs" (która jest rozdzielaną listą nazw pakietów do przeszukania).

Tutaj jest klasą abstrakcyjną, która wykonuje to, czego potrzebujesz: (nie przeszkadza brakujące StringTo<Out1<String>> lub StringURLConnection, to robić to, co sugerują ich nazwy i można korzystać niezależnie abstrakcje wolisz)

public abstract class AbstractURLStreamHandler extends URLStreamHandler { 

    protected abstract StringTo<Out1<String>> dynamicFiles(); 

    protected static void addMyPackage(Class<? extends URLStreamHandler> handlerClass) { 
     // Ensure that we are registered as a url protocol handler for JavaFxCss:/path css files. 
     String was = System.getProperty("java.protocol.handler.pkgs", ""); 
     String pkg = handlerClass.getPackage().getName(); 
     int ind = pkg.lastIndexOf('.'); 
     assert ind != -1 : "You can't add url handlers in the base package"; 
     assert "Handler".equals(handlerClass.getSimpleName()) : "A URLStreamHandler must be in a class named Handler; not " + handlerClass.getSimpleName(); 

     System.setProperty("java.protocol.handler.pkgs", handlerClass.getPackage().getName().substring(0, ind) + 
      (was.isEmpty() ? "" : "|" + was)); 
    } 


    @Override 
    protected URLConnection openConnection(URL u) throws IOException { 
     final String path = u.getPath(); 
     final Out1<String> file = dynamicFiles().get(path); 
     return new StringURLConnection(u, file); 
    } 
} 

Następnie tutaj jest rzeczywista klasa realizacji abstrakcyjne obsługi (dla dynamic: adresami:?.

package xapi.dev.api.dynamic; 

// imports elided for brevity 

public class Handler extends AbstractURLStreamHandler { 

    private static final StringTo<Out1<String>> dynamicFiles = X_Collect.newStringMap(Out1.class, 
     CollectionOptions.asConcurrent(true) 
      .mutable(true) 
      .insertionOrdered(false) 
      .build()); 

    static { 
     addMyPackage(Handler.class); 
    } 

    @Override 
    protected StringTo<Out1<String>> dynamicFiles() { 
     return dynamicFiles; 
    } 

    public static String registerDynamicUrl(String path, Out1<String> contents) { 
     dynamicFiles.put(path, contents); 
     return path; 
    } 

    public static void clearDynamicUrl(String path) { 
     dynamicFiles.remove(path); 
    } 

} 
Powiązane problemy