@@ -84,18 +84,29 @@ public class TMXMapReader {
8484 public static final long FLIPPED_VERTICALLY_FLAG = 0x0000000040000000L ;
8585 public static final long FLIPPED_DIAGONALLY_FLAG = 0x0000000020000000L ;
8686
87- public static final long ALL_FLAGS = FLIPPED_HORIZONTALLY_FLAG
88- | FLIPPED_VERTICALLY_FLAG
89- | FLIPPED_DIAGONALLY_FLAG ;
87+ public static final long ALL_FLAGS =
88+ FLIPPED_HORIZONTALLY_FLAG | FLIPPED_VERTICALLY_FLAG | FLIPPED_DIAGONALLY_FLAG ;
89+
90+ public final TMXMapReaderSettings settings = new TMXMapReaderSettings ();
9091
9192 private Map map ;
9293 private URL xmlPath ;
9394 private String error ;
9495 private final EntityResolver entityResolver = new MapEntityResolver ();
9596 private TreeMap <Integer , TileSet > tilesetPerFirstGid ;
96- public final TMXMapReaderSettings settings = new TMXMapReaderSettings ();
97- private final java .util .Map <String , TileSet > cachedTilesets = new HashMap <>();
98- private final java .util .Map <Class <?>, Unmarshaller > cachedUnmarshallers = new HashMap <>();
97+
98+ /**
99+ * Map of cached tilesets used when {@link TMXMapReaderSettings#reuseCachedTilesets} option is on.
100+ * TODO: case when multiple tilesets have same name but different sources
101+ * @see #setCachedTilesets(java.util.Map)
102+ */
103+ private java .util .Map <String , TileSet > cachedTilesets ;
104+
105+ /**
106+ * Unmarshaller capable of unmarshalling all classes available from context
107+ * @see #unmarshalClass(Node, Class)
108+ */
109+ private final Unmarshaller unmarshaller ;
99110
100111 public static final class TMXMapReaderSettings {
101112
@@ -105,7 +116,10 @@ public static final class TMXMapReaderSettings {
105116 /**
106117 * Constructor for TMXMapReader.
107118 */
108- public TMXMapReader () {
119+ public TMXMapReader () throws JAXBException {
120+ unmarshaller = JAXBContext .newInstance (
121+ Map .class , TileSet .class , Tile .class ,
122+ AnimatedTile .class , ObjectGroup .class , ImageLayer .class ).createUnmarshaller ();
109123 }
110124
111125 String getError () {
@@ -160,14 +174,11 @@ private static double getDoubleAttribute(Node node, String attribname, double de
160174 }
161175
162176 private <T > T unmarshalClass (Node node , Class <T > type ) throws JAXBException {
163- Unmarshaller unmarshaller = cachedUnmarshallers .get (type );
164- if (unmarshaller == null ) {
165- JAXBContext context = JAXBContext .newInstance (type );
166- unmarshaller = context .createUnmarshaller ();
167- cachedUnmarshallers .put (type , unmarshaller );
168- }
169- JAXBElement <T > element = unmarshaller .unmarshal (node , type );
170- return element .getValue ();
177+ // we expect that all classes are already bounded to JAXBContext, so we don't need to create unmarshaller
178+ // dynamicaly cause it's kinda heavy operation
179+ // if you got exception wich tells that SomeClass is not known to this context - just add it to the list
180+ // passed to JAXBContext constructor
181+ return unmarshaller .unmarshal (node , type ).getValue ();
171182 }
172183
173184 private BufferedImage unmarshalImage (Node t , URL baseDir ) throws IOException {
@@ -228,10 +239,7 @@ private TileSet unmarshalTilesetFile(InputStream in, URL file) throws Exception
228239 // There can be only one tileset in a .tsx file.
229240 tsNode = tsNodeList .item (0 );
230241 if (tsNode != null ) {
231- set = unmarshalTileset (tsNode );
232- if (set .getSource () != null ) {
233- System .out .println ("Recursive external tilesets are not supported." );
234- }
242+ set = unmarshalTileset (tsNode , true );
235243 set .setSource (file .toString ());
236244 }
237245
@@ -244,9 +252,25 @@ private TileSet unmarshalTilesetFile(InputStream in, URL file) throws Exception
244252 }
245253
246254 private TileSet unmarshalTileset (Node t ) throws Exception {
255+ return unmarshalTileset (t , false );
256+ }
257+
258+ /**
259+ * @param t xml node to begin unmarshalling from
260+ * @param isExternalTileset is this a node of external tileset located in separate tsx file
261+ */
262+ private TileSet unmarshalTileset (Node t , boolean isExternalTileset ) throws Exception {
247263 TileSet set = unmarshalClass (t , TileSet .class );
248264
249265 String source = set .getSource ();
266+ // if we have a "source" attribute in the external tileset - we ignore it and display a warning
267+ if (source != null && isExternalTileset ) {
268+ source = null ;
269+ set .setSource (null );
270+ System .out .printf ("Warning: recursive external tilesets are not supported - " +
271+ "ignoring source option for tileset %s%n" , set .getName ());
272+ }
273+
250274 if (source != null ) {
251275 source = replacePathSeparator (source );
252276 URL url = URLHelper .resolve (xmlPath , source );
@@ -268,6 +292,10 @@ private TileSet unmarshalTileset(Node t) throws Exception {
268292 final String name = getAttributeValue (t , "name" );
269293
270294 if (settings .reuseCachedTilesets ) {
295+ if (cachedTilesets == null ) {
296+ cachedTilesets = new HashMap <>();
297+ }
298+
271299 set = cachedTilesets .get (name );
272300 if (set != null )
273301 return set ;
@@ -1041,4 +1069,12 @@ private String replacePathSeparator(String path) {
10411069 return path ;
10421070 return path .replace ("/" , File .separator );
10431071 }
1072+
1073+ /**
1074+ * The ability to set cachedTilesets allows cached tilesets to be shared across multiple readers,
1075+ * increasing read speed in a multithreaded environment.
1076+ */
1077+ public void setCachedTilesets (java .util .Map <String , TileSet > cachedTilesets ) {
1078+ this .cachedTilesets = cachedTilesets ;
1079+ }
10441080}
0 commit comments